1 | //===-- LVLocation.cpp ----------------------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // This implements the LVOperation and LVLocation classes. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #include "llvm/DebugInfo/LogicalView/Core/LVLocation.h" |
14 | #include "llvm/DebugInfo/LogicalView/Core/LVReader.h" |
15 | #include "llvm/DebugInfo/LogicalView/Core/LVScope.h" |
16 | #include "llvm/DebugInfo/LogicalView/Core/LVSymbol.h" |
17 | |
18 | using namespace llvm; |
19 | using namespace llvm::logicalview; |
20 | |
21 | #define DEBUG_TYPE "Location" |
22 | |
23 | void LVOperation::print(raw_ostream &OS, bool Full) const {} |
24 | |
25 | // Identify the most common type of operations and print them using a high |
26 | // level format, trying to isolate the DWARF complexity. |
27 | std::string LVOperation::getOperandsDWARFInfo() { |
28 | std::string String; |
29 | raw_string_ostream Stream(String); |
30 | |
31 | auto PrintRegisterInfo = [&](LVSmall Code) { |
32 | //----------------------------------------------------------------------- |
33 | // 2.5.1.1 Literal encodings. |
34 | //----------------------------------------------------------------------- |
35 | if (dwarf::DW_OP_lit0 <= Code && Code <= dwarf::DW_OP_lit31) { |
36 | Stream << format(Fmt: "lit%d" , Vals: Code - dwarf::DW_OP_lit0); |
37 | return; |
38 | } |
39 | |
40 | //----------------------------------------------------------------------- |
41 | // 2.5.1.2 Register values. |
42 | //----------------------------------------------------------------------- |
43 | if (dwarf::DW_OP_breg0 <= Code && Code <= dwarf::DW_OP_breg31) { |
44 | std::string RegisterName(getReader().getRegisterName(Opcode: Code, Operands)); |
45 | Stream << format(Fmt: "breg%d+%d%s" , Vals: Code - dwarf::DW_OP_breg0, Vals: Operands[0], |
46 | Vals: RegisterName.c_str()); |
47 | return; |
48 | } |
49 | |
50 | //----------------------------------------------------------------------- |
51 | // 2.6.1.1.3 Register location descriptions. |
52 | //----------------------------------------------------------------------- |
53 | if (dwarf::DW_OP_reg0 <= Code && Code <= dwarf::DW_OP_reg31) { |
54 | std::string RegisterName(getReader().getRegisterName(Opcode: Code, Operands)); |
55 | Stream << format(Fmt: "reg%d%s" , Vals: Code - dwarf::DW_OP_reg0, |
56 | Vals: RegisterName.c_str()); |
57 | return; |
58 | } |
59 | |
60 | Stream << format(Fmt: "#0x%02x " , Vals: Code) << hexString(Value: Operands[0]) << " " |
61 | << hexString(Value: Operands[1]) << "#" ; |
62 | }; |
63 | |
64 | switch (Opcode) { |
65 | //------------------------------------------------------------------------- |
66 | // 2.5.1.1 Literal encodings. |
67 | //------------------------------------------------------------------------- |
68 | case dwarf::DW_OP_addr: |
69 | Stream << "addr " << hexString(Value: Operands[0]); |
70 | break; |
71 | case dwarf::DW_OP_constu: |
72 | case dwarf::DW_OP_const1u: |
73 | case dwarf::DW_OP_const2u: |
74 | case dwarf::DW_OP_const4u: |
75 | case dwarf::DW_OP_const8u: |
76 | Stream << "const_u " << unsigned(Operands[0]); |
77 | break; |
78 | case dwarf::DW_OP_consts: |
79 | case dwarf::DW_OP_const1s: |
80 | case dwarf::DW_OP_const2s: |
81 | case dwarf::DW_OP_const4s: |
82 | case dwarf::DW_OP_const8s: |
83 | Stream << "const_s " << int(Operands[0]); |
84 | break; |
85 | case dwarf::DW_OP_addrx: |
86 | Stream << "addrx " << unsigned(Operands[0]); |
87 | break; |
88 | case dwarf::DW_OP_constx: |
89 | Stream << "constx " << unsigned(Operands[0]); |
90 | break; |
91 | case dwarf::DW_OP_const_type: |
92 | Stream << "TODO: DW_OP_const_type" ; |
93 | break; |
94 | |
95 | //------------------------------------------------------------------------- |
96 | // 2.5.1.2 Register values. |
97 | //------------------------------------------------------------------------- |
98 | case dwarf::DW_OP_fbreg: |
99 | Stream << "fbreg " << int(Operands[0]); |
100 | break; |
101 | case dwarf::DW_OP_bregx: { |
102 | std::string RegisterName(getReader().getRegisterName(Opcode, Operands)); |
103 | Stream << format(Fmt: "bregx %d%s+%d" , Vals: Operands[0], Vals: RegisterName.c_str(), |
104 | Vals: unsigned(Operands[1])); |
105 | break; |
106 | } |
107 | case dwarf::DW_OP_regval_type: { |
108 | std::string RegisterName(getReader().getRegisterName(Opcode, Operands)); |
109 | Stream << format(Fmt: "regval_type %d%s+%d" , Vals: Operands[0], Vals: RegisterName.c_str(), |
110 | Vals: unsigned(Operands[1])); |
111 | break; |
112 | } |
113 | |
114 | //------------------------------------------------------------------------- |
115 | // 2.5.1.3 Stack operations. |
116 | //------------------------------------------------------------------------- |
117 | case dwarf::DW_OP_dup: |
118 | Stream << "dup" ; |
119 | break; |
120 | case dwarf::DW_OP_drop: |
121 | Stream << "drop" ; |
122 | break; |
123 | case dwarf::DW_OP_pick: |
124 | Stream << "pick " << unsigned(Operands[0]); |
125 | break; |
126 | case dwarf::DW_OP_over: |
127 | Stream << "over" ; |
128 | break; |
129 | case dwarf::DW_OP_swap: |
130 | Stream << "swap" ; |
131 | break; |
132 | case dwarf::DW_OP_rot: |
133 | Stream << "rot" ; |
134 | break; |
135 | case dwarf::DW_OP_deref: |
136 | Stream << "deref" ; |
137 | break; |
138 | case dwarf::DW_OP_deref_size: |
139 | Stream << "deref_size " << unsigned(Operands[0]); |
140 | break; |
141 | case dwarf::DW_OP_deref_type: |
142 | Stream << "deref_type " << unsigned(Operands[0]) << " DIE offset " |
143 | << hexString(Value: Operands[1]); |
144 | break; |
145 | case dwarf::DW_OP_xderef: |
146 | Stream << "xderef" ; |
147 | break; |
148 | case dwarf::DW_OP_xderef_size: |
149 | Stream << "xderef_size " << unsigned(Operands[0]); |
150 | break; |
151 | case dwarf::DW_OP_xderef_type: |
152 | Stream << "xderef_type " << unsigned(Operands[0]) << " DIE offset " |
153 | << hexString(Value: Operands[1]); |
154 | break; |
155 | case dwarf::DW_OP_push_object_address: |
156 | Stream << "push_object_address" ; |
157 | break; |
158 | case dwarf::DW_OP_form_tls_address: |
159 | Stream << "form_tls_address " << hexString(Value: Operands[0]); |
160 | break; |
161 | case dwarf::DW_OP_call_frame_cfa: |
162 | Stream << "call_frame_cfa" ; |
163 | break; |
164 | |
165 | //------------------------------------------------------------------------- |
166 | // 2.5.1.4 Arithmetic and Logical Operations. |
167 | //------------------------------------------------------------------------- |
168 | case dwarf::DW_OP_abs: |
169 | Stream << "abs" ; |
170 | break; |
171 | case dwarf::DW_OP_and: |
172 | Stream << "and" ; |
173 | break; |
174 | case dwarf::DW_OP_div: |
175 | Stream << "div" ; |
176 | break; |
177 | case dwarf::DW_OP_minus: |
178 | Stream << "minus" ; |
179 | break; |
180 | case dwarf::DW_OP_mod: |
181 | Stream << "mod" ; |
182 | break; |
183 | case dwarf::DW_OP_mul: |
184 | Stream << "mul" ; |
185 | break; |
186 | case dwarf::DW_OP_neg: |
187 | Stream << "neg" ; |
188 | break; |
189 | case dwarf::DW_OP_not: |
190 | Stream << "not" ; |
191 | break; |
192 | case dwarf::DW_OP_or: |
193 | Stream << "or" ; |
194 | break; |
195 | case dwarf::DW_OP_plus: |
196 | Stream << "plus" ; |
197 | break; |
198 | case dwarf::DW_OP_plus_uconst: |
199 | Stream << "plus_uconst " << unsigned(Operands[0]); |
200 | break; |
201 | case dwarf::DW_OP_shl: |
202 | Stream << "shl" ; |
203 | break; |
204 | case dwarf::DW_OP_shr: |
205 | Stream << "shr" ; |
206 | break; |
207 | case dwarf::DW_OP_shra: |
208 | Stream << "shra" ; |
209 | break; |
210 | case dwarf::DW_OP_xor: |
211 | Stream << "xor" ; |
212 | break; |
213 | |
214 | //------------------------------------------------------------------------- |
215 | // 2.5.1.5 Control Flow Operations. |
216 | //------------------------------------------------------------------------- |
217 | case dwarf::DW_OP_le: |
218 | Stream << "le" ; |
219 | break; |
220 | case dwarf::DW_OP_ge: |
221 | Stream << "ge" ; |
222 | break; |
223 | case dwarf::DW_OP_eq: |
224 | Stream << "eq" ; |
225 | break; |
226 | case dwarf::DW_OP_lt: |
227 | Stream << "lt" ; |
228 | break; |
229 | case dwarf::DW_OP_gt: |
230 | Stream << "gt" ; |
231 | break; |
232 | case dwarf::DW_OP_ne: |
233 | Stream << "ne" ; |
234 | break; |
235 | case dwarf::DW_OP_skip: |
236 | Stream << "skip " << signed(Operands[0]); |
237 | break; |
238 | case dwarf::DW_OP_bra: |
239 | Stream << "bra " << signed(Operands[0]); |
240 | break; |
241 | case dwarf::DW_OP_call2: |
242 | Stream << "call2 DIE offset " << hexString(Value: Operands[0]); |
243 | break; |
244 | case dwarf::DW_OP_call4: |
245 | Stream << "call4 DIE offset " << hexString(Value: Operands[0]); |
246 | break; |
247 | case dwarf::DW_OP_call_ref: |
248 | Stream << "call_ref DIE offset " << hexString(Value: Operands[0]); |
249 | break; |
250 | |
251 | //------------------------------------------------------------------------- |
252 | // 2.5.1.6 Type Conversions. |
253 | //------------------------------------------------------------------------- |
254 | case dwarf::DW_OP_convert: |
255 | Stream << "convert DIE offset " << hexString(Value: Operands[0]); |
256 | break; |
257 | case dwarf::DW_OP_reinterpret: |
258 | Stream << "reinterpret DIE offset " << hexString(Value: Operands[0]); |
259 | break; |
260 | |
261 | //------------------------------------------------------------------------- |
262 | // 2.5.1.7 Special Operations. |
263 | //------------------------------------------------------------------------- |
264 | case dwarf::DW_OP_nop: |
265 | Stream << "nop" ; |
266 | break; |
267 | case dwarf::DW_OP_entry_value: |
268 | Stream << "TODO: DW_OP_entry_value" ; |
269 | break; |
270 | |
271 | //------------------------------------------------------------------------- |
272 | // 2.6.1.1.3 Register location descriptions. |
273 | //------------------------------------------------------------------------- |
274 | case dwarf::DW_OP_regx: |
275 | Stream << "regx" << getReader().getRegisterName(Opcode, Operands); |
276 | break; |
277 | |
278 | //------------------------------------------------------------------------- |
279 | // 2.6.1.1.4 Implicit location descriptions. |
280 | //------------------------------------------------------------------------- |
281 | case dwarf::DW_OP_stack_value: |
282 | Stream << "stack_value" ; |
283 | break; |
284 | case dwarf::DW_OP_implicit_value: |
285 | Stream << "TODO: DW_OP_implicit_value" ; |
286 | break; |
287 | case dwarf::DW_OP_implicit_pointer: |
288 | Stream << "implicit_pointer DIE offset " << hexString(Value: Operands[0]) << " " |
289 | << int(Operands[1]); |
290 | break; |
291 | |
292 | //------------------------------------------------------------------------- |
293 | // 2.6.1.2 Composite location descriptions. |
294 | //------------------------------------------------------------------------- |
295 | case dwarf::DW_OP_piece: |
296 | Stream << "piece " << int(Operands[0]); |
297 | break; |
298 | case dwarf::DW_OP_bit_piece: |
299 | Stream << "bit_piece " << int(Operands[0]) << " offset " |
300 | << int(Operands[1]); |
301 | break; |
302 | |
303 | //------------------------------------------------------------------------- |
304 | // GNU extensions. |
305 | //------------------------------------------------------------------------- |
306 | case dwarf::DW_OP_GNU_entry_value: |
307 | Stream << "gnu_entry_value " ; |
308 | PrintRegisterInfo(dwarf::DW_OP_reg0); |
309 | break; |
310 | case dwarf::DW_OP_GNU_push_tls_address: |
311 | Stream << "gnu_push_tls_address " << hexString(Value: Operands[0]); |
312 | break; |
313 | case dwarf::DW_OP_GNU_addr_index: |
314 | Stream << "gnu_addr_index " << unsigned(Operands[0]); |
315 | break; |
316 | case dwarf::DW_OP_GNU_const_index: |
317 | Stream << "gnu_const_index " << unsigned(Operands[0]); |
318 | break; |
319 | |
320 | //------------------------------------------------------------------------- |
321 | // Member location. |
322 | //------------------------------------------------------------------------- |
323 | case LVLocationMemberOffset: |
324 | Stream << "offset " << int(Operands[0]); |
325 | break; |
326 | |
327 | //------------------------------------------------------------------------- |
328 | // Missing location. |
329 | //------------------------------------------------------------------------- |
330 | case dwarf::DW_OP_hi_user: |
331 | Stream << "missing" ; |
332 | break; |
333 | |
334 | //------------------------------------------------------------------------- |
335 | // Register values. |
336 | //------------------------------------------------------------------------- |
337 | default: |
338 | PrintRegisterInfo(Opcode); |
339 | break; |
340 | } |
341 | |
342 | return String; |
343 | } |
344 | |
345 | // Identify the most common type of operations and print them using a high |
346 | // level format, trying to isolate the CodeView complexity. |
347 | std::string LVOperation::getOperandsCodeViewInfo() { |
348 | std::string String; |
349 | raw_string_ostream Stream(String); |
350 | |
351 | // Get original CodeView operation code. |
352 | uint16_t OperationCode = getCodeViewOperationCode(Code: Opcode); |
353 | |
354 | switch (OperationCode) { |
355 | // Operands: [Offset]. |
356 | case codeview::SymbolKind::S_DEFRANGE_FRAMEPOINTER_REL: |
357 | Stream << "frame_pointer_rel " << int(Operands[0]); |
358 | break; |
359 | case codeview::SymbolKind::S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE: |
360 | Stream << "frame_pointer_rel_full_scope " << int(Operands[0]); |
361 | break; |
362 | |
363 | // Operands: [Register]. |
364 | case codeview::SymbolKind::S_DEFRANGE_REGISTER: |
365 | Stream << "register " << getReader().getRegisterName(Opcode, Operands); |
366 | break; |
367 | case codeview::SymbolKind::S_DEFRANGE_SUBFIELD_REGISTER: |
368 | Stream << "subfield_register " |
369 | << getReader().getRegisterName(Opcode, Operands); |
370 | break; |
371 | |
372 | // Operands: [Register, Offset]. |
373 | case codeview::SymbolKind::S_DEFRANGE_REGISTER_REL: |
374 | Stream << "register_rel " << getReader().getRegisterName(Opcode, Operands) |
375 | << " offset " << int(Operands[1]); |
376 | break; |
377 | |
378 | // Operands: [Program]. |
379 | case codeview::SymbolKind::S_DEFRANGE: |
380 | Stream << "frame " << int(Operands[0]); |
381 | break; |
382 | case codeview::SymbolKind::S_DEFRANGE_SUBFIELD: |
383 | Stream << "subfield " << int(Operands[0]); |
384 | break; |
385 | |
386 | default: |
387 | Stream << format(Fmt: "#0x%02x: " , Vals: Opcode) << hexString(Value: Operands[0]) << " " |
388 | << hexString(Value: Operands[1]) << "#" ; |
389 | break; |
390 | } |
391 | |
392 | return String; |
393 | } |
394 | |
395 | namespace { |
396 | const char *const KindBaseClassOffset = "BaseClassOffset" ; |
397 | const char *const KindBaseClassStep = "BaseClassStep" ; |
398 | const char *const KindClassOffset = "ClassOffset" ; |
399 | const char *const KindFixedAddress = "FixedAddress" ; |
400 | const char *const KindMissingInfo = "Missing" ; |
401 | const char *const KindOperation = "Operation" ; |
402 | const char *const KindOperationList = "OperationList" ; |
403 | const char *const KindRegister = "Register" ; |
404 | const char *const KindUndefined = "Undefined" ; |
405 | } // end anonymous namespace |
406 | |
407 | //===----------------------------------------------------------------------===// |
408 | // DWARF location information. |
409 | //===----------------------------------------------------------------------===// |
410 | const char *LVLocation::kind() const { |
411 | const char *Kind = KindUndefined; |
412 | if (getIsBaseClassOffset()) |
413 | Kind = KindBaseClassOffset; |
414 | else if (getIsBaseClassStep()) |
415 | Kind = KindBaseClassStep; |
416 | else if (getIsClassOffset()) |
417 | Kind = KindClassOffset; |
418 | else if (getIsFixedAddress()) |
419 | Kind = KindFixedAddress; |
420 | else if (getIsGapEntry()) |
421 | Kind = KindMissingInfo; |
422 | else if (getIsOperation()) |
423 | Kind = KindOperation; |
424 | else if (getIsOperationList()) |
425 | Kind = KindOperationList; |
426 | else if (getIsRegister()) |
427 | Kind = KindRegister; |
428 | return Kind; |
429 | } |
430 | |
431 | std::string LVLocation::getIntervalInfo() const { |
432 | static const char *const Question = "?" ; |
433 | std::string String; |
434 | raw_string_ostream Stream(String); |
435 | if (getIsAddressRange()) |
436 | Stream << "{Range}" ; |
437 | |
438 | auto PrintLine = [&](const LVLine *Line) { |
439 | if (Line) { |
440 | std::string TheLine; |
441 | TheLine = Line->lineNumberAsStringStripped(); |
442 | Stream << TheLine.c_str(); |
443 | } else { |
444 | Stream << Question; |
445 | } |
446 | }; |
447 | |
448 | Stream << " Lines " ; |
449 | PrintLine(getLowerLine()); |
450 | Stream << ":" ; |
451 | PrintLine(getUpperLine()); |
452 | |
453 | if (options().getAttributeOffset()) |
454 | // Print the active range (low pc and high pc). |
455 | Stream << " [" << hexString(Value: getLowerAddress()) << ":" |
456 | << hexString(Value: getUpperAddress()) << "]" ; |
457 | |
458 | return String; |
459 | } |
460 | |
461 | // Validate the ranges associated with the location. |
462 | bool LVLocation::validateRanges() { |
463 | // Traverse the locations and validate them against the address to line |
464 | // mapping in the current compile unit. Record those invalid ranges. |
465 | // A valid range must meet the following conditions: |
466 | // a) line(lopc) <= line(hipc) |
467 | // b) line(lopc) and line(hipc) are valid. |
468 | |
469 | if (!hasAssociatedRange()) |
470 | return true; |
471 | |
472 | LVLineRange Range = getReaderCompileUnit()->lineRange(Location: this); |
473 | LVLine *LowLine = Range.first; |
474 | LVLine *HighLine = Range.second; |
475 | if (LowLine) |
476 | setLowerLine(LowLine); |
477 | else { |
478 | setIsInvalidLower(); |
479 | return false; |
480 | } |
481 | if (HighLine) |
482 | setUpperLine(HighLine); |
483 | else { |
484 | setIsInvalidUpper(); |
485 | return false; |
486 | } |
487 | // Check for a valid interval. |
488 | if (LowLine->getLineNumber() > HighLine->getLineNumber()) { |
489 | setIsInvalidRange(); |
490 | return false; |
491 | } |
492 | |
493 | return true; |
494 | } |
495 | |
496 | bool LVLocation::calculateCoverage(LVLocations *Locations, unsigned &Factor, |
497 | float &Percentage) { |
498 | if (!options().getAttributeCoverage() && !Locations) |
499 | return false; |
500 | |
501 | // Calculate the coverage depending on the kind of location. We have |
502 | // the simple and composed locations. |
503 | if (Locations->size() == 1) { |
504 | // Simple: fixed address, class offset, stack offset. |
505 | LVLocation *Location = Locations->front(); |
506 | // Some types of locations do not have specific kind. Now is the time |
507 | // to set those types, depending on the operation type. |
508 | Location->updateKind(); |
509 | if (Location->getIsLocationSimple()) { |
510 | Factor = 100; |
511 | Percentage = 100; |
512 | return true; |
513 | } |
514 | } |
515 | |
516 | // Composed locations. |
517 | LVAddress LowerAddress = 0; |
518 | LVAddress UpperAddress = 0; |
519 | for (const LVLocation *Location : *Locations) |
520 | // Do not include locations representing a gap. |
521 | if (!Location->getIsGapEntry()) { |
522 | LowerAddress = Location->getLowerAddress(); |
523 | UpperAddress = Location->getUpperAddress(); |
524 | Factor += (UpperAddress > LowerAddress) ? UpperAddress - LowerAddress |
525 | : LowerAddress - UpperAddress; |
526 | } |
527 | |
528 | Percentage = 0; |
529 | return false; |
530 | } |
531 | |
532 | void LVLocation::printRaw(raw_ostream &OS, bool Full) const { |
533 | // Print the active range (low pc and high pc). |
534 | OS << " [" << hexString(Value: getLowerAddress()) << ":" |
535 | << hexString(Value: getUpperAddress()) << "]\n" ; |
536 | // Print any DWARF operations. |
537 | printRawExtra(OS, Full); |
538 | } |
539 | |
540 | void LVLocation::printInterval(raw_ostream &OS, bool Full) const { |
541 | if (hasAssociatedRange()) |
542 | OS << getIntervalInfo(); |
543 | } |
544 | |
545 | void LVLocation::print(raw_ostream &OS, bool Full) const { |
546 | if (getReader().doPrintLocation(Location: this)) { |
547 | LVObject::print(OS, Full); |
548 | printExtra(OS, Full); |
549 | } |
550 | } |
551 | |
552 | void LVLocation::(raw_ostream &OS, bool Full) const { |
553 | printInterval(OS, Full); |
554 | OS << "\n" ; |
555 | } |
556 | |
557 | //===----------------------------------------------------------------------===// |
558 | // DWARF location for a symbol. |
559 | //===----------------------------------------------------------------------===// |
560 | // Add a Location Entry. |
561 | void LVLocationSymbol::addObject(LVAddress LowPC, LVAddress HighPC, |
562 | LVUnsigned SectionOffset, |
563 | uint64_t LocDescOffset) { |
564 | setLowerAddress(LowPC); |
565 | setUpperAddress(HighPC); |
566 | |
567 | // Record the offset where the location information begins. |
568 | setOffset(LocDescOffset ? LocDescOffset : SectionOffset); |
569 | |
570 | // A -1 HighPC value, indicates no range. |
571 | if (HighPC == LVAddress(UINT64_MAX)) |
572 | setIsDiscardedRange(); |
573 | |
574 | // Update the location kind, using the DWARF attribute. |
575 | setKind(); |
576 | } |
577 | |
578 | // Add a Location Record. |
579 | void LVLocationSymbol::addObject(LVSmall Opcode, |
580 | ArrayRef<LVUnsigned> Operands) { |
581 | if (!Entries) |
582 | Entries = std::make_unique<LVOperations>(); |
583 | Entries->push_back(Elt: getReader().createOperation(OpCode: Opcode, Operands)); |
584 | } |
585 | |
586 | // Based on the DWARF attribute, define the location kind. |
587 | void LVLocation::setKind() { |
588 | switch (getAttr()) { |
589 | case dwarf::DW_AT_data_member_location: |
590 | setIsClassOffset(); |
591 | break; |
592 | case dwarf::DW_AT_location: |
593 | // Depending on the operand, we have a fixed address. |
594 | setIsFixedAddress(); |
595 | break; |
596 | default: |
597 | break; |
598 | } |
599 | // For those symbols with absolute location information, ignore any |
600 | // gaps in their location description; that is the case with absolute |
601 | // memory addresses and members located at specific offsets. |
602 | if (hasAssociatedRange()) |
603 | getParentSymbol()->setFillGaps(); |
604 | } |
605 | |
606 | void LVLocationSymbol::updateKind() { |
607 | // Update the location type for simple ones. |
608 | if (Entries && Entries->size() == 1) { |
609 | if (dwarf::DW_OP_fbreg == Entries->front()->getOpcode()) |
610 | setIsStackOffset(); |
611 | } |
612 | } |
613 | |
614 | void LVLocationSymbol::(raw_ostream &OS, bool Full) const { |
615 | if (Entries) |
616 | for (const LVOperation *Operation : *Entries) |
617 | Operation->print(OS, Full); |
618 | } |
619 | |
620 | // Print location (formatted version). |
621 | void LVLocation::print(LVLocations *Locations, raw_ostream &OS, bool Full) { |
622 | if (!Locations || Locations->empty()) |
623 | return; |
624 | |
625 | // Print the symbol coverage. |
626 | if (options().getAttributeCoverage()) { |
627 | // The location entries are contained within a symbol. Get a location, |
628 | // to access basic information about indentation, parent, etc. |
629 | LVLocation *Location = Locations->front(); |
630 | LVSymbol *Symbol = Location->getParentSymbol(); |
631 | float Percentage = Symbol->getCoveragePercentage(); |
632 | |
633 | // The coverage is dependent on the kind of location. |
634 | std::string String; |
635 | raw_string_ostream Stream(String); |
636 | Stream << format(Fmt: "%.2f%%" , Vals: Percentage); |
637 | if (!Location->getIsLocationSimple()) |
638 | Stream << format(Fmt: " (%d/%d)" , Vals: Symbol->getCoverageFactor(), |
639 | Vals: Symbol->getParentScope()->getCoverageFactor()); |
640 | Symbol->printAttributes(OS, Full, Name: "{Coverage} " , Parent: Symbol, Value: StringRef(String), |
641 | /*UseQuotes=*/false, |
642 | /*PrintRef=*/false); |
643 | } |
644 | |
645 | // Print the symbol location, including the missing entries. |
646 | if (getReader().doPrintLocation(/*Location=*/nullptr)) |
647 | for (const LVLocation *Location : *Locations) |
648 | Location->print(OS, Full); |
649 | } |
650 | |
651 | void LVLocationSymbol::(raw_ostream &OS, bool Full) const { |
652 | OS << "{Location}" ; |
653 | if (getIsCallSite()) |
654 | OS << " -> CallSite" ; |
655 | printInterval(OS, Full); |
656 | OS << "\n" ; |
657 | |
658 | // Print location entries. |
659 | if (Full && Entries) { |
660 | bool CodeViewLocation = getParentSymbol()->getHasCodeViewLocation(); |
661 | std::stringstream Stream; |
662 | std::string Leading; |
663 | for (LVOperation *Operation : *Entries) { |
664 | Stream << Leading |
665 | << (CodeViewLocation ? Operation->getOperandsCodeViewInfo() |
666 | : Operation->getOperandsDWARFInfo()); |
667 | Leading = ", " ; |
668 | } |
669 | printAttributes(OS, Full, Name: "{Entry} " , Parent: const_cast<LVLocationSymbol *>(this), |
670 | Value: StringRef(Stream.str()), |
671 | /*UseQuotes=*/false, |
672 | /*PrintRef=*/false); |
673 | } |
674 | } |
675 | |