OLD | NEW |
| (Empty) |
1 // Copyright (c) 2011 The Native Client Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #region | |
6 | |
7 using System; | |
8 using System.Collections.Generic; | |
9 using System.Diagnostics; | |
10 using NaClVsx; | |
11 | |
12 #endregion | |
13 | |
14 namespace Google.NaClVsx.DebugSupport.DWARF { | |
15 /// <summary> | |
16 /// The interface implemented by this class lives in | |
17 /// NaClVsx.DebugHelpers/DwarfParser.h | |
18 /// </summary> | |
19 class DwarfReaderImpl : IDwarfReader { | |
20 public DwarfReaderImpl(SymbolDatabase db) { | |
21 db_ = db; | |
22 } | |
23 | |
24 #region Implementation of IDwarfReader | |
25 | |
26 public void StartCompilationUnit() { | |
27 // File and directory ids are unique only within a compilation unit. | |
28 dirs_.Clear(); | |
29 compilationUnitIndex_++; | |
30 } | |
31 | |
32 public void EndCompilationUnit() {} | |
33 | |
34 public void StartDIE(ulong parent, ulong offset, DwarfTag tag) { | |
35 var entry = | |
36 new DebugInfoEntry { | |
37 Key = offset, | |
38 OuterScope = scopeStack_.PeekOrDefault(), | |
39 ParentKey = parent, | |
40 Tag = tag | |
41 }; | |
42 | |
43 db_.Entries[offset] = entry; | |
44 } | |
45 | |
46 public void EndDIE(ulong offset) { | |
47 var entry = db_.Entries[offset]; | |
48 | |
49 // If this DIE is a scope, it should at this point be at the top of the | |
50 // scope stack. | |
51 if (scopeStack_.PeekOrDefault() == entry) { | |
52 scopeStack_.Pop(); | |
53 | |
54 // Add a transition back to the parent scope. This may get overwritten | |
55 // if a sibling scope starts where this one ends, but that's cool. | |
56 // | |
57 // Note: we can only do this if the scope has a high pc value. Labels | |
58 // don't. | |
59 object highpc; | |
60 if (entry.Attributes.TryGetValue( | |
61 DwarfAttribute.DW_AT_high_pc, out highpc)) { | |
62 if (db_.ScopeTransitions.ContainsKey((ulong) highpc)) { | |
63 // This can happen if a parent and child scope end on the same pc | |
64 // value. The parent wins, so overwrite the previous entry. | |
65 db_.ScopeTransitions[(ulong) highpc].Entry = entry.OuterScope; | |
66 } else { | |
67 db_.ScopeTransitions.Add( | |
68 (ulong) highpc, | |
69 new SymbolDatabase.ScopeTransition { | |
70 Address = (ulong) highpc, | |
71 Entry = entry.OuterScope | |
72 }); | |
73 } | |
74 } | |
75 } | |
76 } | |
77 | |
78 public void ProcessAttribute(ulong offset, | |
79 ulong parent, | |
80 DwarfAttribute attr, | |
81 object data) { | |
82 var entry = db_.Entries[offset]; | |
83 | |
84 var key = attributeIndex_++; | |
85 db_.Attributes.Add( | |
86 key, | |
87 new SymbolDatabase.DebugInfoAttribute { | |
88 Key = key, | |
89 ParentKey = parent, | |
90 Tag = attr, | |
91 Value = data | |
92 }); | |
93 entry.Attributes.Add(attr, data); | |
94 | |
95 | |
96 // If we have a PC range, it's time to make a new scope | |
97 if (attr == DwarfAttribute.DW_AT_low_pc) { | |
98 var addr = (ulong) data; | |
99 | |
100 // Add a scope transition for this entry. | |
101 // Replace any existing scope transition at the point where | |
102 // this entry starts. Existing transitions are expected--it | |
103 // just means that this entry starts where its sibling ends. | |
104 if (db_.ScopeTransitions.ContainsKey(addr)) { | |
105 db_.ScopeTransitions[addr].Entry = entry; | |
106 } else { | |
107 db_.ScopeTransitions.Add( | |
108 addr, | |
109 new SymbolDatabase.ScopeTransition { | |
110 Address = addr, | |
111 Entry = entry | |
112 }); | |
113 } | |
114 // This entry may already be on the scope track if it has low_pc and | |
115 // ranges. | |
116 if (scopeStack_.PeekOrDefault() != entry) { | |
117 scopeStack_.Push(db_.Entries[parent]); | |
118 } | |
119 } else if (attr == DwarfAttribute.DW_AT_ranges) { | |
120 // We can't make the scope transition because ranges are parsed on a | |
121 // different code path, so we'll handle it during a post-processing | |
122 // step. | |
123 // This entry may already be on the scope track if it has low_pc as | |
124 // well as ranges. | |
125 if (scopeStack_.PeekOrDefault() != entry) { | |
126 scopeStack_.Push(db_.Entries[parent]); | |
127 } | |
128 } | |
129 } | |
130 | |
131 public void DefineDir(string name, uint dirNum) { | |
132 try { | |
133 dirs_[dirNum] = name; | |
134 } | |
135 catch (Exception e) { | |
136 Debug.WriteLine(e.Message); | |
137 } | |
138 } | |
139 | |
140 public void DefineFile(string name, | |
141 int fileNum, | |
142 uint dirNum) { | |
143 var key = MakeFileKey((uint) fileNum); | |
144 string relpath; | |
145 if (!dirs_.TryGetValue(dirNum, out relpath)) { | |
146 relpath = ""; | |
147 } | |
148 db_.Files.Add( | |
149 key, | |
150 new SymbolDatabase.SourceFile { | |
151 Key = key, | |
152 Filename = name, | |
153 RelativePath = relpath, | |
154 CurrentAbsolutePath = name | |
155 }); | |
156 } | |
157 | |
158 public void AddLine(ulong address, | |
159 ulong length, | |
160 uint fileNum, | |
161 uint lineNum, | |
162 uint columnNum) { | |
163 // | |
164 // There are several cases in the C++ standard library where a line entry | |
165 // has zero length. This appears to happen when a line of code is | |
166 // elided for whatever reason. The problem is that the address might be | |
167 // perfectly valid for a different line of code, which would lead to | |
168 // duplicate entries in our location table. So if length is zero, bail. | |
169 // | |
170 if (length == 0) { | |
171 return; | |
172 } | |
173 | |
174 // | |
175 // Add the address and location to our locations table. | |
176 // | |
177 try { | |
178 var | |
179 sourceLocation = new SymbolDatabase.SourceLocation { | |
180 StartAddress = address, | |
181 Length = length, | |
182 SourceFileKey = MakeFileKey(fileNum), | |
183 Line = lineNum, | |
184 Column = columnNum, | |
185 }; | |
186 | |
187 db_.Locations.Add(address, sourceLocation); | |
188 } | |
189 catch (Exception e) { | |
190 Debug.WriteLine(e.Message); | |
191 } | |
192 } | |
193 | |
194 public void AddLocListEntry(ulong offset, | |
195 bool isFirstEntry, | |
196 ulong lowPc, | |
197 ulong highPc, | |
198 byte[] data) { | |
199 if (isFirstEntry) { | |
200 currentLocList_ = offset; | |
201 db_.LocLists.Add(offset, new List<SymbolDatabase.LocListEntry>()); | |
202 } | |
203 var list = db_.LocLists[currentLocList_]; | |
204 list.Add( | |
205 new SymbolDatabase.LocListEntry { | |
206 StartAddress = lowPc, | |
207 EndAddress = highPc, | |
208 Data = data | |
209 }); | |
210 } | |
211 | |
212 public bool BeginCfiEntry(ulong address) { | |
213 currentFrame_ = new SymbolDatabase.CallFrame {Address = address}; | |
214 return true; | |
215 } | |
216 | |
217 public bool AddCfiRule(ulong address, | |
218 int reg, | |
219 IDwarfReader.CfiRuleType ruleType, | |
220 int baseRegister, | |
221 int offset, | |
222 byte[] expression) { | |
223 currentFrame_.Rules.Add( | |
224 new SymbolDatabase.CallFrame.Rule { | |
225 Address = address, | |
226 BaseRegister = baseRegister, | |
227 Expression = expression, | |
228 Offset = offset, | |
229 RegisterId = reg, | |
230 RuleType = ruleType | |
231 }); | |
232 return true; | |
233 } | |
234 | |
235 public bool EndCfiEntry() { | |
236 if (currentFrame_ == null) { | |
237 throw new DwarfParseException("Mismatched begin/end CFI entries"); | |
238 } | |
239 db_.CallFrames.Add(currentFrame_.Address, currentFrame_); | |
240 | |
241 currentFrame_ = null; | |
242 return true; | |
243 } | |
244 | |
245 public void AddRangeListEntry(ulong offset, | |
246 ulong baseAddress, | |
247 ulong lowPC, | |
248 ulong highPC) { | |
249 if (lowPC != highPC) { | |
250 if (!db_.RangeLists.ContainsKey(offset)) { | |
251 db_.RangeLists.Add(offset, new Dictionary<ulong, RangeListEntry>()); | |
252 } | |
253 if (!db_.RangeLists[offset].ContainsKey(lowPC)) { | |
254 var entry = new RangeListEntry { | |
255 Offset = offset, | |
256 BaseAddress = baseAddress, | |
257 LowPC = lowPC, | |
258 HighPC = highPC | |
259 }; | |
260 db_.RangeLists[offset].Add(lowPC, entry); | |
261 } | |
262 } | |
263 } | |
264 | |
265 private ulong MakeFileKey(uint fileNum) { | |
266 return ((ulong) compilationUnitIndex_ << 32) | fileNum; | |
267 } | |
268 | |
269 #endregion | |
270 | |
271 #region Private Implementation | |
272 | |
273 private readonly SymbolDatabase db_; | |
274 | |
275 private readonly Dictionary<uint, string> dirs_ = | |
276 new Dictionary<uint, string>(); | |
277 | |
278 private readonly Stack<DebugInfoEntry> scopeStack_ = | |
279 new Stack<DebugInfoEntry>(); | |
280 | |
281 private ulong attributeIndex_; | |
282 private ushort compilationUnitIndex_; | |
283 private SymbolDatabase.CallFrame currentFrame_; | |
284 private ulong currentLocList_; | |
285 | |
286 #endregion | |
287 } | |
288 | |
289 internal class DwarfParseException : Exception { | |
290 public DwarfParseException(string msg) : base(msg) {} | |
291 } | |
292 } | |
OLD | NEW |