1 /*
2 * Copyright 2009-2012, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Copyright 2012-2014, Rene Gollent, rene@gollent.com.
4 * Distributed under the terms of the MIT License.
5 */
6
7
8 #include "DwarfFile.h"
9
10 #include <algorithm>
11 #include <new>
12
13 #include <AutoDeleter.h>
14 #include <Entry.h>
15 #include <FindDirectory.h>
16 #include <Path.h>
17 #include <PathFinder.h>
18
19 #include "AttributeClasses.h"
20 #include "AttributeValue.h"
21 #include "AbbreviationTable.h"
22 #include "CfaContext.h"
23 #include "CompilationUnit.h"
24 #include "DataReader.h"
25 #include "DwarfExpressionEvaluator.h"
26 #include "DwarfTargetInterface.h"
27 #include "ElfFile.h"
28 #include "TagNames.h"
29 #include "TargetAddressRangeList.h"
30 #include "Tracing.h"
31 #include "Variant.h"
32
33
34 // #pragma mark - AutoSectionPutter
35
36
37 class AutoSectionPutter {
38 public:
AutoSectionPutter(ElfFile * elfFile,ElfSection * elfSection)39 AutoSectionPutter(ElfFile* elfFile, ElfSection* elfSection)
40 :
41 fElfFile(elfFile),
42 fElfSection(elfSection)
43 {
44 }
45
~AutoSectionPutter()46 ~AutoSectionPutter()
47 {
48 if (fElfSection != NULL)
49 fElfFile->PutSection(fElfSection);
50 }
51
52 private:
53 ElfFile* fElfFile;
54 ElfSection* fElfSection;
55 };
56
57
58 // #pragma mark - ExpressionEvaluationContext
59
60
61 struct DwarfFile::ExpressionEvaluationContext
62 : DwarfExpressionEvaluationContext {
63 public:
ExpressionEvaluationContextDwarfFile::ExpressionEvaluationContext64 ExpressionEvaluationContext(DwarfFile* file, CompilationUnit* unit,
65 uint8 addressSize, bool isBigEndian, DIESubprogram* subprogramEntry,
66 const DwarfTargetInterface* targetInterface,
67 target_addr_t instructionPointer, target_addr_t objectPointer,
68 bool hasObjectPointer, target_addr_t framePointer,
69 target_addr_t relocationDelta)
70 :
71 DwarfExpressionEvaluationContext(targetInterface, addressSize, isBigEndian,
72 relocationDelta),
73 fFile(file),
74 fUnit(unit),
75 fSubprogramEntry(subprogramEntry),
76 fInstructionPointer(instructionPointer),
77 fObjectPointer(objectPointer),
78 fHasObjectPointer(hasObjectPointer),
79 fFramePointer(framePointer),
80 fFrameBasePointer(0),
81 fFrameBaseEvaluated(false)
82 {
83 }
84
GetObjectAddressDwarfFile::ExpressionEvaluationContext85 virtual bool GetObjectAddress(target_addr_t& _address)
86 {
87 if (!fHasObjectPointer)
88 return false;
89
90 _address = fObjectPointer;
91 return true;
92 }
93
GetFrameAddressDwarfFile::ExpressionEvaluationContext94 virtual bool GetFrameAddress(target_addr_t& _address)
95 {
96 if (fFramePointer == 0)
97 return false;
98
99 _address = fFramePointer;
100 return true;
101 }
102
GetFrameBaseAddressDwarfFile::ExpressionEvaluationContext103 virtual bool GetFrameBaseAddress(target_addr_t& _address)
104 {
105 if (fFrameBaseEvaluated) {
106 if (fFrameBasePointer == 0)
107 return false;
108
109 _address = fFrameBasePointer;
110 return true;
111 }
112
113 // set flag already to prevent recursion for a buggy expression
114 fFrameBaseEvaluated = true;
115
116 // get the subprogram's frame base location
117 if (fSubprogramEntry == NULL)
118 return false;
119 const LocationDescription* location = fSubprogramEntry->FrameBase();
120 if (!location->IsValid())
121 return false;
122
123 // get the expression
124 const void* expression;
125 off_t expressionLength;
126 status_t error = fFile->_GetLocationExpression(fUnit, location,
127 fInstructionPointer, expression, expressionLength);
128 if (error != B_OK)
129 return false;
130
131 // evaluate the expression
132 DwarfExpressionEvaluator evaluator(this);
133 error = evaluator.Evaluate(expression, expressionLength,
134 fFrameBasePointer);
135 if (error != B_OK)
136 return false;
137
138 TRACE_EXPR(" -> frame base: %" B_PRIx64 "\n", fFrameBasePointer);
139
140 _address = fFrameBasePointer;
141 return true;
142 }
143
GetTLSAddressDwarfFile::ExpressionEvaluationContext144 virtual bool GetTLSAddress(target_addr_t localAddress,
145 target_addr_t& _address)
146 {
147 // TODO:...
148 return false;
149 }
150
GetCallTargetDwarfFile::ExpressionEvaluationContext151 virtual status_t GetCallTarget(uint64 offset, uint8 refType,
152 const void*& _block, off_t& _size)
153 {
154 // resolve the entry
155 DebugInfoEntry* entry = fFile->_ResolveReference(fUnit, offset, refType);
156 if (entry == NULL)
157 return B_ENTRY_NOT_FOUND;
158
159 // get the location description
160 LocationDescription* location = entry->GetLocationDescription();
161 if (location == NULL || !location->IsValid()) {
162 _block = NULL;
163 _size = 0;
164 return B_OK;
165 }
166
167 // get the expression
168 return fFile->_GetLocationExpression(fUnit, location,
169 fInstructionPointer, _block, _size);
170 }
171
172 private:
173 DwarfFile* fFile;
174 CompilationUnit* fUnit;
175 DIESubprogram* fSubprogramEntry;
176 target_addr_t fInstructionPointer;
177 target_addr_t fObjectPointer;
178 bool fHasObjectPointer;
179 target_addr_t fFramePointer;
180 target_addr_t fFrameBasePointer;
181 bool fFrameBaseEvaluated;
182 };
183
184
185 // #pragma mark - FDEAugmentation
186
187
188 struct DwarfFile::FDEAugmentation {
189 // Currently we're ignoring all augmentation data.
190 };
191
192
193 // #pragma mark - CIEAugmentation
194
195
196 enum {
197 CFI_AUGMENTATION_DATA = 0x01,
198 CFI_AUGMENTATION_LANGUAGE_SPECIFIC_DATA = 0x02,
199 CFI_AUGMENTATION_PERSONALITY = 0x04,
200 CFI_AUGMENTATION_ADDRESS_POINTER_FORMAT = 0x08,
201 };
202
203
204 // encodings for CFI_AUGMENTATION_ADDRESS_POINTER_FORMAT
205 enum {
206 CFI_ADDRESS_FORMAT_ABSOLUTE = 0x00,
207 CFI_ADDRESS_FORMAT_UNSIGNED_LEB128 = 0x01,
208 CFI_ADDRESS_FORMAT_UNSIGNED_16 = 0x02,
209 CFI_ADDRESS_FORMAT_UNSIGNED_32 = 0x03,
210 CFI_ADDRESS_FORMAT_UNSIGNED_64 = 0x04,
211 CFI_ADDRESS_FORMAT_SIGNED = 0x08,
212 CFI_ADDRESS_FORMAT_SIGNED_LEB128 =
213 CFI_ADDRESS_FORMAT_UNSIGNED_LEB128 | CFI_ADDRESS_FORMAT_SIGNED,
214 CFI_ADDRESS_FORMAT_SIGNED_16 =
215 CFI_ADDRESS_FORMAT_UNSIGNED_16 | CFI_ADDRESS_FORMAT_SIGNED,
216 CFI_ADDRESS_FORMAT_SIGNED_32 =
217 CFI_ADDRESS_FORMAT_UNSIGNED_32 | CFI_ADDRESS_FORMAT_SIGNED,
218 CFI_ADDRESS_FORMAT_SIGNED_64 =
219 CFI_ADDRESS_FORMAT_UNSIGNED_64 | CFI_ADDRESS_FORMAT_SIGNED
220 };
221
222
223 enum {
224 CFI_ADDRESS_TYPE_PC_RELATIVE = 0x10,
225 CFI_ADDRESS_TYPE_TEXT_RELATIVE = 0x20,
226 CFI_ADDRESS_TYPE_DATA_RELATIVE = 0x30,
227 CFI_ADDRESS_TYPE_FUNCTION_RELATIVE = 0x40,
228 CFI_ADDRESS_TYPE_ALIGNED = 0x50,
229 CFI_ADDRESS_TYPE_INDIRECT = 0x80
230 };
231
232
233 struct DwarfFile::CIEAugmentation {
CIEAugmentationDwarfFile::CIEAugmentation234 CIEAugmentation()
235 :
236 fString(NULL),
237 fFlags(0),
238 fAddressEncoding(CFI_ADDRESS_FORMAT_ABSOLUTE)
239 {
240 // we default to absolute address format since that corresponds
241 // to the DWARF standard for .debug_frame. In gcc's case, however,
242 // .eh_frame will generally override that via augmentation 'R'
243 }
244
InitDwarfFile::CIEAugmentation245 void Init(DataReader& dataReader)
246 {
247 fFlags = 0;
248 fString = dataReader.ReadString();
249 }
250
ReadDwarfFile::CIEAugmentation251 status_t Read(DataReader& dataReader)
252 {
253 if (fString == NULL || *fString == '\0')
254 return B_OK;
255
256 if (*fString == 'z') {
257 // There are augmentation data.
258 fFlags |= CFI_AUGMENTATION_DATA;
259 const char* string = fString + 1;
260
261 // read the augmentation data block -- it is preceeded by an
262 // LEB128 indicating the length of the data block
263 uint64 length = dataReader.ReadUnsignedLEB128(0);
264 uint64 remaining = length;
265 // let's see what data we have to expect
266
267 TRACE_CFI(" %" B_PRIu64 " bytes of augmentation data\n", length);
268 while (*string != '\0') {
269 switch (*string) {
270 case 'L':
271 fFlags |= CFI_AUGMENTATION_LANGUAGE_SPECIFIC_DATA;
272 dataReader.Read<char>(0);
273 --remaining;
274 break;
275 case 'P':
276 {
277 char tempEncoding = fAddressEncoding;
278 fAddressEncoding = dataReader.Read<char>(0);
279 off_t offset = dataReader.Offset();
280 ReadEncodedAddress(dataReader, NULL, NULL, true);
281 fAddressEncoding = tempEncoding;
282 remaining -= dataReader.Offset() - offset + 1;
283 break;
284 }
285 case 'R':
286 fFlags |= CFI_AUGMENTATION_ADDRESS_POINTER_FORMAT;
287 fAddressEncoding = dataReader.Read<char>(0);
288 --remaining;
289 break;
290 default:
291 WARNING("Encountered unsupported augmentation '%c' "
292 " while parsing CIE augmentation string %s\n",
293 *string, fString);
294 return B_UNSUPPORTED;
295 }
296 string++;
297 }
298
299 // we should have read through all of the augmentation data
300 // at this point, if not, something is wrong.
301 if (remaining != 0 || dataReader.HasOverflow()) {
302 WARNING("Error while reading CIE Augmentation, expected "
303 "%" B_PRIu64 " bytes of augmentation data, but read "
304 "%" B_PRIu64 " bytes.\n", length, length - remaining);
305 return B_BAD_DATA;
306 }
307
308 return B_OK;
309 }
310
311 // nothing to do
312 if (strcmp(fString, "eh") == 0)
313 return B_OK;
314
315 // something we can't handle
316 return B_UNSUPPORTED;
317 }
318
ReadFDEDataDwarfFile::CIEAugmentation319 status_t ReadFDEData(DataReader& dataReader,
320 FDEAugmentation& fdeAugmentation)
321 {
322 if (!HasData())
323 return B_OK;
324
325 // read the augmentation data block -- it is preceeded by an LEB128
326 // indicating the length of the data block
327 uint64 length = dataReader.ReadUnsignedLEB128(0);
328 dataReader.Skip(length);
329 // TODO: Actually read what is interesting for us!
330
331 TRACE_CFI(" %" B_PRIu64 " bytes of augmentation data\n", length);
332
333 if (dataReader.HasOverflow())
334 return B_BAD_DATA;
335
336 return B_OK;
337 }
338
StringDwarfFile::CIEAugmentation339 const char* String() const
340 {
341 return fString;
342 }
343
HasDataDwarfFile::CIEAugmentation344 bool HasData() const
345 {
346 return (fFlags & CFI_AUGMENTATION_DATA) != 0;
347 }
348
HasFDEAddressFormatDwarfFile::CIEAugmentation349 bool HasFDEAddressFormat() const
350 {
351 return (fFlags & CFI_AUGMENTATION_ADDRESS_POINTER_FORMAT) != 0;
352 }
353
FDEAddressOffsetDwarfFile::CIEAugmentation354 target_addr_t FDEAddressOffset(ElfFile* file,
355 ElfSection* debugFrameSection) const
356 {
357 switch (FDEAddressType()) {
358 case CFI_ADDRESS_FORMAT_ABSOLUTE:
359 TRACE_CFI("FDE address format: absolute, ");
360 return 0;
361 case CFI_ADDRESS_TYPE_PC_RELATIVE:
362 TRACE_CFI("FDE address format: PC relative, ");
363 return debugFrameSection->LoadAddress();
364 case CFI_ADDRESS_TYPE_FUNCTION_RELATIVE:
365 TRACE_CFI("FDE address format: function relative, ");
366 return 0;
367 case CFI_ADDRESS_TYPE_TEXT_RELATIVE:
368 TRACE_CFI("FDE address format: text relative, ");
369 return file->TextSegment()->LoadAddress();
370 case CFI_ADDRESS_TYPE_DATA_RELATIVE:
371 TRACE_CFI("FDE address format: data relative, ");
372 return file->DataSegment()->LoadAddress();
373 case CFI_ADDRESS_TYPE_ALIGNED:
374 case CFI_ADDRESS_TYPE_INDIRECT:
375 TRACE_CFI("FDE address format: UNIMPLEMENTED, ");
376 // TODO: implement
377 // -- note: type indirect is currently not generated
378 return 0;
379 }
380
381 return 0;
382 }
383
FDEAddressTypeDwarfFile::CIEAugmentation384 uint8 FDEAddressType() const
385 {
386 return fAddressEncoding & 0x70;
387 }
388
ReadEncodedAddressDwarfFile::CIEAugmentation389 target_addr_t ReadEncodedAddress(DataReader &reader,
390 ElfFile* file, ElfSection* debugFrameSection,
391 bool valueOnly = false) const
392 {
393 target_addr_t address = valueOnly ? 0 : FDEAddressOffset(file,
394 debugFrameSection);
395 switch (fAddressEncoding & 0x0f) {
396 case CFI_ADDRESS_FORMAT_ABSOLUTE:
397 address += reader.ReadAddress(0);
398 TRACE_CFI(" target address: %" B_PRId64 "\n", address);
399 break;
400 case CFI_ADDRESS_FORMAT_UNSIGNED_LEB128:
401 address += reader.ReadUnsignedLEB128(0);
402 TRACE_CFI(" unsigned LEB128: %" B_PRId64 "\n", address);
403 break;
404 case CFI_ADDRESS_FORMAT_SIGNED_LEB128:
405 address += reader.ReadSignedLEB128(0);
406 TRACE_CFI(" signed LEB128: %" B_PRId64 "\n", address);
407 break;
408 case CFI_ADDRESS_FORMAT_UNSIGNED_16:
409 address += reader.Read<uint16>(0);
410 TRACE_CFI(" unsigned 16-bit: %" B_PRId64 "\n", address);
411 break;
412 case CFI_ADDRESS_FORMAT_SIGNED_16:
413 address += reader.Read<int16>(0);
414 TRACE_CFI(" signed 16-bit: %" B_PRId64 "\n", address);
415 break;
416 case CFI_ADDRESS_FORMAT_UNSIGNED_32:
417 address += reader.Read<uint32>(0);
418 TRACE_CFI(" unsigned 32-bit: %" B_PRId64 "\n", address);
419 break;
420 case CFI_ADDRESS_FORMAT_SIGNED_32:
421 address += reader.Read<int32>(0);
422 TRACE_CFI(" signed 32-bit: %" B_PRId64 "\n", address);
423 break;
424 case CFI_ADDRESS_FORMAT_UNSIGNED_64:
425 address += reader.Read<uint64>(0);
426 TRACE_CFI(" unsigned 64-bit: %" B_PRId64 "\n", address);
427 break;
428 case CFI_ADDRESS_FORMAT_SIGNED_64:
429 address += reader.Read<int64>(0);
430 TRACE_CFI(" signed 64-bit: %" B_PRId64 "\n", address);
431 break;
432 }
433
434 return address;
435 }
436
437
438 private:
439 const char* fString;
440 uint32 fFlags;
441 int8 fAddressEncoding;
442 };
443
444
445 // #pragma mark - FDELookupInfo
446
447
448 struct DwarfFile::FDELookupInfo {
449 public:
FDELookupInfoDwarfFile::FDELookupInfo450 FDELookupInfo(target_addr_t start, target_addr_t end,
451 uint64 fdeOffset, uint64 cieOffset, bool ehFrame)
452 :
453 start(start),
454 end(end),
455 fdeOffset(fdeOffset),
456 cieOffset(cieOffset),
457 ehFrame(ehFrame)
458 {
459 }
460
CompareFDEInfosDwarfFile::FDELookupInfo461 static int CompareFDEInfos(const FDELookupInfo* a, const FDELookupInfo* b)
462 {
463 if (a->start < b->start)
464 return -1;
465 else if (a->start > b->start)
466 return 1;
467
468 return 0;
469 }
470
ContainsAddressDwarfFile::FDELookupInfo471 inline bool ContainsAddress(target_addr_t address) const
472 {
473 return address >= start && address < end;
474 }
475
476 target_addr_t start;
477 target_addr_t end;
478 uint64 fdeOffset;
479 uint64 cieOffset;
480 bool ehFrame;
481 };
482
483
484 // #pragma mark - DwarfFile
485
486
DwarfFile()487 DwarfFile::DwarfFile()
488 :
489 fName(NULL),
490 fAlternateName(NULL),
491 fElfFile(NULL),
492 fAlternateElfFile(NULL),
493 fDebugInfoSection(NULL),
494 fDebugAbbrevSection(NULL),
495 fDebugAddressSection(NULL),
496 fDebugStringSection(NULL),
497 fDebugStrOffsetsSection(NULL),
498 fDebugRangesSection(NULL),
499 fDebugLineSection(NULL),
500 fDebugLineStrSection(NULL),
501 fDebugFrameSection(NULL),
502 fEHFrameSection(NULL),
503 fDebugLocationSection(NULL),
504 fDebugPublicTypesSection(NULL),
505 fDebugTypesSection(NULL),
506 fCompilationUnits(20, true),
507 fTypeUnits(),
508 fDebugFrameInfos(100, true),
509 fEHFrameInfos(100, true),
510 fTypesSectionRequired(false),
511 fFinished(false),
512 fItaniumEHFrameFormat(false),
513 fFinishError(B_OK)
514 {
515 }
516
517
~DwarfFile()518 DwarfFile::~DwarfFile()
519 {
520 while (AbbreviationTable* table = fAbbreviationTables.RemoveHead())
521 delete table;
522
523 if (fElfFile != NULL) {
524 ElfFile* debugInfoFile = fAlternateElfFile != NULL
525 ? fAlternateElfFile : fElfFile;
526
527 debugInfoFile->PutSection(fDebugInfoSection);
528 debugInfoFile->PutSection(fDebugAbbrevSection);
529 debugInfoFile->PutSection(fDebugAddressSection);
530 debugInfoFile->PutSection(fDebugStringSection);
531 debugInfoFile->PutSection(fDebugStrOffsetsSection);
532 debugInfoFile->PutSection(fDebugRangesSection);
533 debugInfoFile->PutSection(fDebugLineSection);
534 debugInfoFile->PutSection(fDebugLineStrSection);
535 debugInfoFile->PutSection(fDebugFrameSection);
536 fElfFile->PutSection(fEHFrameSection);
537 debugInfoFile->PutSection(fDebugLocationSection);
538 debugInfoFile->PutSection(fDebugPublicTypesSection);
539 delete fElfFile;
540 delete fAlternateElfFile;
541 }
542
543 TypeUnitTableEntry* entry = fTypeUnits.Clear(true);
544 while (entry != NULL) {
545 TypeUnitTableEntry* nextEntry = entry->next;
546 delete entry;
547 entry = nextEntry;
548 }
549
550 free(fName);
551 free(fAlternateName);
552 }
553
554
555 status_t
StartLoading(const char * fileName,BString & _requiredExternalFile)556 DwarfFile::StartLoading(const char* fileName, BString& _requiredExternalFile)
557 {
558 fName = strdup(fileName);
559 if (fName == NULL)
560 return B_NO_MEMORY;
561
562 status_t error = fTypeUnits.Init();
563 if (error != B_OK)
564 return error;
565
566 // load the ELF file
567 fElfFile = new(std::nothrow) ElfFile;
568 if (fElfFile == NULL)
569 return B_NO_MEMORY;
570
571 error = fElfFile->Init(fileName);
572 if (error != B_OK)
573 return error;
574
575 return _LocateDebugInfo(_requiredExternalFile);
576 }
577
578
579 status_t
Load(uint8 addressSize,bool isBigEndian,const BString & externalInfoFilePath)580 DwarfFile::Load(uint8 addressSize, bool isBigEndian, const BString& externalInfoFilePath)
581 {
582 status_t error = B_OK;
583 if (fDebugInfoSection == NULL) {
584 BString path;
585 error = _LocateDebugInfo(path, externalInfoFilePath.IsEmpty()
586 ? NULL : externalInfoFilePath.String());
587 if (error != B_OK)
588 return error;
589 }
590
591 ElfFile* debugInfoFile = fAlternateElfFile != NULL
592 ? fAlternateElfFile : fElfFile;
593
594 // non mandatory sections
595 fDebugAddressSection = debugInfoFile->GetSection(".debug_addr");
596 fDebugStringSection = debugInfoFile->GetSection(".debug_str");
597 fDebugStrOffsetsSection = debugInfoFile->GetSection(".debug_str_offsets");
598 fDebugRangesSection = debugInfoFile->GetSection(".debug_ranges");
599 fDebugLineSection = debugInfoFile->GetSection(".debug_line");
600 fDebugLineStrSection = debugInfoFile->GetSection(".debug_line_str");
601 fDebugFrameSection = debugInfoFile->GetSection(".debug_frame");
602
603 if (fDebugFrameSection != NULL) {
604 error = _ParseFrameSection(fDebugFrameSection,
605 addressSize, isBigEndian,
606 false, fDebugFrameInfos);
607 if (error != B_OK)
608 return error;
609 }
610
611 // .eh_frame doesn't appear to get copied into separate debug
612 // info files properly, therefore always use it off the main
613 // executable image
614 if (fEHFrameSection == NULL)
615 fEHFrameSection = fElfFile->GetSection(".eh_frame");
616
617 if (fEHFrameSection != NULL) {
618 error = _ParseFrameSection(fEHFrameSection,
619 addressSize, isBigEndian,
620 true, fEHFrameInfos);
621 if (error != B_OK)
622 return error;
623 }
624
625 fDebugLocationSection = debugInfoFile->GetSection(".debug_loc");
626 fDebugPublicTypesSection = debugInfoFile->GetSection(".debug_pubtypes");
627
628 if (fDebugInfoSection == NULL) {
629 fFinished = true;
630 return B_OK;
631 }
632
633 error = _ParseDebugInfoSection(addressSize, isBigEndian);
634 if (error != B_OK)
635 return error;
636
637 if (fTypesSectionRequired) {
638 fDebugTypesSection = debugInfoFile->GetSection(".debug_types");
639 if (fDebugTypesSection == NULL) {
640 WARNING(".debug_types section required but missing.\n");
641 return B_BAD_DATA;
642 }
643 error = _ParseTypesSection(addressSize, isBigEndian);
644 if (error != B_OK)
645 return error;
646 }
647
648 return B_OK;
649 }
650
651
652 status_t
FinishLoading(uint8 addressSize,bool isBigEndian)653 DwarfFile::FinishLoading(uint8 addressSize, bool isBigEndian)
654 {
655 if (fFinished)
656 return B_OK;
657 if (fFinishError != B_OK)
658 return fFinishError;
659
660 status_t error;
661 for (TypeUnitTable::Iterator it = fTypeUnits.GetIterator();
662 TypeUnitTableEntry* entry = it.Next();) {
663 error = _FinishUnit(entry->unit);
664 if (error != B_OK)
665 return fFinishError = error;
666 }
667
668 for (int32 i = 0; CompilationUnit* unit = fCompilationUnits.ItemAt(i);
669 i++) {
670 error = _FinishUnit(unit);
671 if (error != B_OK)
672 return fFinishError = error;
673 }
674
675 _ParsePublicTypesInfo(addressSize, isBigEndian);
676
677 fFinished = true;
678 return B_OK;
679 }
680
681
682 int32
CountCompilationUnits() const683 DwarfFile::CountCompilationUnits() const
684 {
685 return fCompilationUnits.CountItems();
686 }
687
688
689 CompilationUnit*
CompilationUnitAt(int32 index) const690 DwarfFile::CompilationUnitAt(int32 index) const
691 {
692 return fCompilationUnits.ItemAt(index);
693 }
694
695
696 CompilationUnit*
CompilationUnitForDIE(const DebugInfoEntry * entry) const697 DwarfFile::CompilationUnitForDIE(const DebugInfoEntry* entry) const
698 {
699 // find the root of the tree the entry lives in
700 while (entry != NULL && entry->Parent() != NULL)
701 entry = entry->Parent();
702
703 // that should be the compilation unit entry
704 const DIECompileUnitBase* unitEntry
705 = dynamic_cast<const DIECompileUnitBase*>(entry);
706 if (unitEntry == NULL)
707 return NULL;
708
709 // find the compilation unit
710 for (int32 i = 0; CompilationUnit* unit = fCompilationUnits.ItemAt(i);
711 i++) {
712 if (unit->UnitEntry() == unitEntry)
713 return unit;
714 }
715
716 return NULL;
717 }
718
719
720 TargetAddressRangeList*
ResolveRangeList(CompilationUnit * unit,uint64 offset) const721 DwarfFile::ResolveRangeList(CompilationUnit* unit, uint64 offset) const
722 {
723 if (unit == NULL || fDebugRangesSection == NULL)
724 return NULL;
725
726 if (offset >= (uint64)fDebugRangesSection->Size())
727 return NULL;
728
729 TargetAddressRangeList* ranges = new(std::nothrow) TargetAddressRangeList;
730 if (ranges == NULL) {
731 ERROR("Out of memory.\n");
732 return NULL;
733 }
734 BReference<TargetAddressRangeList> rangesReference(ranges, true);
735
736 target_addr_t baseAddress = unit->AddressRangeBase();
737 target_addr_t maxAddress = unit->MaxAddress();
738
739 DataReader dataReader((uint8*)fDebugRangesSection->Data() + offset,
740 fDebugRangesSection->Size() - offset, unit->AddressSize(), unit->IsBigEndian());
741 while (true) {
742 target_addr_t start = dataReader.ReadAddress(0);
743 target_addr_t end = dataReader.ReadAddress(0);
744 if (dataReader.HasOverflow())
745 return NULL;
746
747 if (start == 0 && end == 0)
748 break;
749 if (start == maxAddress) {
750 baseAddress = end;
751 continue;
752 }
753 if (start == end)
754 continue;
755
756 if (!ranges->AddRange(baseAddress + start, end - start)) {
757 ERROR("Out of memory.\n");
758 return NULL;
759 }
760 }
761
762 return rangesReference.Detach();
763 }
764
765
766 status_t
UnwindCallFrame(CompilationUnit * unit,uint8 addressSize,bool isBigEndian,DIESubprogram * subprogramEntry,target_addr_t location,const DwarfTargetInterface * inputInterface,DwarfTargetInterface * outputInterface,target_addr_t & _framePointer)767 DwarfFile::UnwindCallFrame(CompilationUnit* unit, uint8 addressSize, bool isBigEndian,
768 DIESubprogram* subprogramEntry, target_addr_t location,
769 const DwarfTargetInterface* inputInterface,
770 DwarfTargetInterface* outputInterface, target_addr_t& _framePointer)
771 {
772 FDELookupInfo* info = _GetContainingFDEInfo(location);
773 if (info == NULL)
774 return B_ENTRY_NOT_FOUND;
775
776 return _UnwindCallFrame(unit, addressSize, isBigEndian,
777 subprogramEntry, location, info,
778 inputInterface, outputInterface, _framePointer);
779 }
780
781
782 status_t
EvaluateExpression(CompilationUnit * unit,uint8 addressSize,bool isBigEndian,DIESubprogram * subprogramEntry,const void * expression,off_t expressionLength,const DwarfTargetInterface * targetInterface,target_addr_t instructionPointer,target_addr_t framePointer,target_addr_t valueToPush,bool pushValue,target_addr_t & _result)783 DwarfFile::EvaluateExpression(CompilationUnit* unit, uint8 addressSize, bool isBigEndian,
784 DIESubprogram* subprogramEntry, const void* expression,
785 off_t expressionLength, const DwarfTargetInterface* targetInterface,
786 target_addr_t instructionPointer, target_addr_t framePointer,
787 target_addr_t valueToPush, bool pushValue, target_addr_t& _result)
788 {
789 ExpressionEvaluationContext context(this, unit, addressSize, isBigEndian,
790 subprogramEntry, targetInterface, instructionPointer, 0, false,
791 framePointer, 0);
792 DwarfExpressionEvaluator evaluator(&context);
793
794 if (pushValue && evaluator.Push(valueToPush) != B_OK)
795 return B_NO_MEMORY;
796
797 return evaluator.Evaluate(expression, expressionLength, _result);
798 }
799
800
801 status_t
ResolveLocation(CompilationUnit * unit,uint8 addressSize,bool isBigEndian,DIESubprogram * subprogramEntry,const LocationDescription * location,const DwarfTargetInterface * targetInterface,target_addr_t instructionPointer,target_addr_t objectPointer,bool hasObjectPointer,target_addr_t framePointer,target_addr_t relocationDelta,ValueLocation & _result)802 DwarfFile::ResolveLocation(CompilationUnit* unit, uint8 addressSize, bool isBigEndian,
803 DIESubprogram* subprogramEntry, const LocationDescription* location,
804 const DwarfTargetInterface* targetInterface,
805 target_addr_t instructionPointer, target_addr_t objectPointer,
806 bool hasObjectPointer, target_addr_t framePointer,
807 target_addr_t relocationDelta, ValueLocation& _result)
808 {
809 // get the expression
810 const void* expression;
811 off_t expressionLength;
812 status_t error = _GetLocationExpression(unit, location, instructionPointer,
813 expression, expressionLength);
814 if (error != B_OK)
815 return error;
816
817 // evaluate it
818 ExpressionEvaluationContext context(this, unit, addressSize, isBigEndian,
819 subprogramEntry, targetInterface, instructionPointer, objectPointer,
820 hasObjectPointer, framePointer, relocationDelta);
821 DwarfExpressionEvaluator evaluator(&context);
822 return evaluator.EvaluateLocation(expression, expressionLength,
823 _result);
824 }
825
826
827 status_t
EvaluateConstantValue(CompilationUnit * unit,uint8 addressSize,bool isBigEndian,DIESubprogram * subprogramEntry,const ConstantAttributeValue * value,const DwarfTargetInterface * targetInterface,target_addr_t instructionPointer,target_addr_t framePointer,BVariant & _result)828 DwarfFile::EvaluateConstantValue(CompilationUnit* unit, uint8 addressSize, bool isBigEndian,
829 DIESubprogram* subprogramEntry, const ConstantAttributeValue* value,
830 const DwarfTargetInterface* targetInterface,
831 target_addr_t instructionPointer, target_addr_t framePointer,
832 BVariant& _result)
833 {
834 if (!value->IsValid())
835 return B_BAD_VALUE;
836
837 switch (value->attributeClass) {
838 case ATTRIBUTE_CLASS_CONSTANT:
839 _result.SetTo(value->constant);
840 return B_OK;
841 case ATTRIBUTE_CLASS_STRING:
842 _result.SetTo(value->string);
843 return B_OK;
844 case ATTRIBUTE_CLASS_BLOCK:
845 {
846 target_addr_t result;
847 status_t error = EvaluateExpression(unit, addressSize, isBigEndian,
848 subprogramEntry, value->block.data, value->block.length,
849 targetInterface, instructionPointer, framePointer, 0, false,
850 result);
851 if (error != B_OK)
852 return error;
853
854 _result.SetTo(result);
855 return B_OK;
856 }
857 default:
858 return B_BAD_VALUE;
859 }
860 }
861
862
863 status_t
EvaluateDynamicValue(CompilationUnit * unit,uint8 addressSize,bool isBigEndian,DIESubprogram * subprogramEntry,const DynamicAttributeValue * value,const DwarfTargetInterface * targetInterface,target_addr_t instructionPointer,target_addr_t framePointer,BVariant & _result,DIEType ** _type)864 DwarfFile::EvaluateDynamicValue(CompilationUnit* unit, uint8 addressSize, bool isBigEndian,
865 DIESubprogram* subprogramEntry, const DynamicAttributeValue* value,
866 const DwarfTargetInterface* targetInterface,
867 target_addr_t instructionPointer, target_addr_t framePointer,
868 BVariant& _result, DIEType** _type)
869 {
870 if (!value->IsValid())
871 return B_BAD_VALUE;
872
873 DIEType* dummyType;
874 if (_type == NULL)
875 _type = &dummyType;
876
877 switch (value->attributeClass) {
878 case ATTRIBUTE_CLASS_CONSTANT:
879 _result.SetTo(value->constant);
880 *_type = NULL;
881 return B_OK;
882
883 case ATTRIBUTE_CLASS_REFERENCE:
884 {
885 // TODO: The specs are a bit fuzzy on this one: "the value is a
886 // reference to another entity whose value is the value of the
887 // attribute". Supposedly that also means e.g. if the referenced
888 // entity is a variable, we should read the value of that variable.
889 // ATM we only check for the types that can have a DW_AT_const_value
890 // attribute and evaluate it, if present.
891 DebugInfoEntry* entry = value->reference;
892 if (entry == NULL)
893 return B_BAD_VALUE;
894
895 const ConstantAttributeValue* constantValue = NULL;
896 DIEType* type = NULL;
897
898 switch (entry->Tag()) {
899 case DW_TAG_constant:
900 {
901 DIEConstant* constantEntry
902 = dynamic_cast<DIEConstant*>(entry);
903 constantValue = constantEntry->ConstValue();
904 type = constantEntry->GetType();
905 break;
906 }
907 case DW_TAG_enumerator:
908 constantValue = dynamic_cast<DIEEnumerator*>(entry)
909 ->ConstValue();
910 if (DIEEnumerationType* enumerationType
911 = dynamic_cast<DIEEnumerationType*>(
912 entry->Parent())) {
913 type = enumerationType->GetType();
914 }
915 break;
916 case DW_TAG_formal_parameter:
917 {
918 DIEFormalParameter* parameterEntry
919 = dynamic_cast<DIEFormalParameter*>(entry);
920 constantValue = parameterEntry->ConstValue();
921 type = parameterEntry->GetType();
922 break;
923 }
924 case DW_TAG_template_value_parameter:
925 {
926 DIETemplateValueParameter* parameterEntry
927 = dynamic_cast<DIETemplateValueParameter*>(entry);
928 constantValue = parameterEntry->ConstValue();
929 type = parameterEntry->GetType();
930 break;
931 }
932 case DW_TAG_variable:
933 {
934 DIEVariable* variableEntry
935 = dynamic_cast<DIEVariable*>(entry);
936 constantValue = variableEntry->ConstValue();
937 type = variableEntry->GetType();
938 break;
939 }
940 default:
941 return B_BAD_VALUE;
942 }
943
944 if (constantValue == NULL || !constantValue->IsValid())
945 return B_BAD_VALUE;
946
947 status_t error = EvaluateConstantValue(unit, addressSize, isBigEndian,
948 subprogramEntry, constantValue, targetInterface,
949 instructionPointer, framePointer, _result);
950 if (error != B_OK)
951 return error;
952
953 *_type = type;
954 return B_OK;
955 }
956
957 case ATTRIBUTE_CLASS_BLOCK:
958 {
959 target_addr_t result;
960 status_t error = EvaluateExpression(unit, addressSize, isBigEndian,
961 subprogramEntry, value->block.data, value->block.length,
962 targetInterface, instructionPointer, framePointer, 0, false,
963 result);
964 if (error != B_OK)
965 return error;
966
967 _result.SetTo(result);
968 *_type = NULL;
969 return B_OK;
970 }
971
972 default:
973 return B_BAD_VALUE;
974 }
975 }
976
977
978 status_t
_ParseDebugInfoSection(uint8 _addressSize,bool isBigEndian)979 DwarfFile::_ParseDebugInfoSection(uint8 _addressSize, bool isBigEndian)
980 {
981 // iterate through the debug info section
982 DataReader dataReader(fDebugInfoSection->Data(),
983 fDebugInfoSection->Size(), _addressSize, isBigEndian);
984
985 while (dataReader.HasData()) {
986 off_t unitHeaderOffset = dataReader.Offset();
987 bool dwarf64;
988 uint64 unitLength = dataReader.ReadInitialLength(dwarf64);
989
990 off_t unitLengthOffset = dataReader.Offset();
991 // the unitLength starts here
992
993 if (unitLengthOffset + unitLength
994 > (uint64)fDebugInfoSection->Size()) {
995 WARNING("\"%s\": Invalid compilation unit length.\n", fName);
996 break;
997 }
998
999 int version = dataReader.Read<uint16>(0);
1000 if (version >= 5) {
1001 uint8 unitType = dataReader.Read<uint8>(0);
1002 if (unitType != DW_UT_compile) {
1003 WARNING("\"%s\": Unsupported unit type %d\n",
1004 fName, unitType);
1005 return B_UNSUPPORTED;
1006 }
1007 }
1008
1009 off_t abbrevOffset;
1010 uint8 addressSize;
1011
1012 if (version >= 5) {
1013 addressSize = dataReader.Read<uint8>(0);
1014 abbrevOffset = dwarf64
1015 ? dataReader.Read<uint64>(0)
1016 : dataReader.Read<uint32>(0);
1017 } else {
1018 abbrevOffset = dwarf64
1019 ? dataReader.Read<uint64>(0)
1020 : dataReader.Read<uint32>(0);
1021 addressSize = dataReader.Read<uint8>(0);
1022 }
1023
1024 if (dataReader.HasOverflow()) {
1025 WARNING("\"%s\": Unexpected end of data in compilation unit "
1026 "header.\n", fName);
1027 break;
1028 }
1029
1030 TRACE_DIE("DWARF%d compilation unit: version %d, length: %" B_PRIu64
1031 ", abbrevOffset: %" B_PRIdOFF ", address size: %d\n",
1032 dwarf64 ? 64 : 32, version, unitLength, abbrevOffset, addressSize);
1033
1034 if (version < 2 || version > 4) {
1035 WARNING("\"%s\": Unsupported compilation unit version: %d\n",
1036 fName, version);
1037 break;
1038 }
1039
1040 if (addressSize != 4 && addressSize != 8) {
1041 WARNING("\"%s\": Unsupported address size: %d\n", fName,
1042 addressSize);
1043 break;
1044 }
1045 dataReader.SetAddressSize(addressSize);
1046
1047 off_t unitContentOffset = dataReader.Offset();
1048
1049 // create a compilation unit object
1050 CompilationUnit* unit = new(std::nothrow) CompilationUnit(
1051 unitHeaderOffset, unitContentOffset,
1052 unitLength + (unitLengthOffset - unitHeaderOffset),
1053 abbrevOffset, addressSize, isBigEndian, dwarf64);
1054 if (unit == NULL || !fCompilationUnits.AddItem(unit)) {
1055 delete unit;
1056 return B_NO_MEMORY;
1057 }
1058
1059 // parse the debug info for the unit
1060 status_t error = _ParseCompilationUnit(unit);
1061 if (error != B_OK)
1062 return error;
1063
1064 dataReader.SeekAbsolute(unitLengthOffset + unitLength);
1065 }
1066
1067 return B_OK;
1068 }
1069
1070
1071 status_t
_ParseTypesSection(uint8 _addressSize,bool isBigEndian)1072 DwarfFile::_ParseTypesSection(uint8 _addressSize, bool isBigEndian)
1073 {
1074 DataReader dataReader(fDebugTypesSection->Data(),
1075 fDebugTypesSection->Size(), _addressSize, isBigEndian);
1076 while (dataReader.HasData()) {
1077 off_t unitHeaderOffset = dataReader.Offset();
1078 bool dwarf64;
1079 uint64 unitLength = dataReader.ReadInitialLength(dwarf64);
1080
1081 off_t unitLengthOffset = dataReader.Offset();
1082 // the unitLength starts here
1083
1084 if (unitLengthOffset + unitLength
1085 > (uint64)fDebugTypesSection->Size()) {
1086 WARNING("Invalid type unit length, offset %#" B_PRIx64 ".\n",
1087 unitHeaderOffset);
1088 break;
1089 }
1090
1091 int version = dataReader.Read<uint16>(0);
1092 off_t abbrevOffset = dwarf64
1093 ? dataReader.Read<uint64>(0)
1094 : dataReader.Read<uint32>(0);
1095 uint8 addressSize = dataReader.Read<uint8>(0);
1096
1097 if (dataReader.HasOverflow()) {
1098 WARNING("Unexpected end of data in type unit header at %#"
1099 B_PRIx64 ".\n", unitHeaderOffset);
1100 break;
1101 }
1102
1103 dataReader.SetAddressSize(addressSize);
1104
1105 uint64 signature = dataReader.Read<uint64>(0);
1106
1107 off_t typeOffset = dwarf64
1108 ? dataReader.Read<uint64>(0)
1109 : dataReader.Read<uint32>(0);
1110
1111 off_t unitContentOffset = dataReader.Offset();
1112
1113 TRACE_DIE("DWARF%d type unit: version %d, length: %" B_PRIu64
1114 ", abbrevOffset: %" B_PRIdOFF ", address size: %d, "
1115 "signature: %#" B_PRIx64 ", type offset: %" B_PRIu64 "\n",
1116 dwarf64 ? 64 : 32, version, unitLength, abbrevOffset, addressSize,
1117 signature, typeOffset);
1118
1119 if (version > 4) {
1120 WARNING("\"%s\": Unsupported type unit version: %d\n",
1121 fName, version);
1122 break;
1123 }
1124
1125 if (addressSize != 4 && addressSize != 8) {
1126 WARNING("\"%s\": Unsupported address size: %d\n", fName,
1127 addressSize);
1128 break;
1129 }
1130
1131 // create a type unit object
1132 TypeUnit* unit = new(std::nothrow) TypeUnit(
1133 unitHeaderOffset, unitContentOffset,
1134 unitLength + (unitLengthOffset - unitHeaderOffset),
1135 abbrevOffset, typeOffset, addressSize, isBigEndian,
1136 signature, dwarf64);
1137 if (unit == NULL)
1138 return B_NO_MEMORY;
1139
1140 // parse the debug info for the unit
1141 status_t error = _ParseTypeUnit(unit);
1142 if (error != B_OK)
1143 return error;
1144
1145 // TODO: it should theoretically never happen that we get a duplicate,
1146 // but it wouldn't hurt to check since that situation would potentially
1147 // be problematic.
1148 if (fTypeUnits.Lookup(signature) == NULL) {
1149 TypeUnitTableEntry* entry = new(std::nothrow)
1150 TypeUnitTableEntry(signature, unit);
1151 if (entry == NULL)
1152 return B_NO_MEMORY;
1153
1154 fTypeUnits.Insert(entry);
1155 }
1156
1157 dataReader.SeekAbsolute(unitLengthOffset + unitLength);
1158 }
1159
1160 return B_OK;
1161 }
1162
1163
1164 status_t
_ParseFrameSection(ElfSection * section,uint8 addressSize,bool isBigEndian,bool ehFrame,FDEInfoList & infos)1165 DwarfFile::_ParseFrameSection(ElfSection* section, uint8 addressSize, bool isBigEndian,
1166 bool ehFrame, FDEInfoList& infos)
1167 {
1168 if (ehFrame) {
1169 fItaniumEHFrameFormat = section->IsWritable();
1170 // Crude heuristic for recognizing GCC 4 (Itanium ABI) style
1171 // .eh_frame sections. The ones generated by GCC 2 are writable,
1172 // the ones generated by GCC 4 aren't.
1173 }
1174
1175 DataReader dataReader((uint8*)section->Data(),
1176 section->Size(), addressSize, isBigEndian);
1177
1178 while (dataReader.BytesRemaining() > 0) {
1179 // length
1180 bool dwarf64;
1181 off_t entryOffset = dataReader.Offset();
1182 uint64 length = dataReader.ReadInitialLength(dwarf64);
1183
1184 TRACE_CFI("DwarfFile::_ParseFrameSection(): offset: %" B_PRIdOFF
1185 ", length: %" B_PRId64 "\n", entryOffset, length);
1186
1187 if (length > (uint64)dataReader.BytesRemaining())
1188 return B_BAD_DATA;
1189 off_t lengthOffset = dataReader.Offset();
1190
1191 // If the length is 0, it means a terminator of the CIE.
1192 // Then just skip this .debug_frame/.eh_frame section.
1193 if (length == 0)
1194 return B_OK;
1195
1196 // CIE ID/CIE pointer
1197 uint64 cieID = dwarf64
1198 ? dataReader.Read<uint64>(0) : dataReader.Read<uint32>(0);
1199
1200 // In .debug_frame ~0 indicates a CIE, in .eh_frame 0 does.
1201 if (ehFrame
1202 ? cieID == 0
1203 : (dwarf64
1204 ? cieID == 0xffffffffffffffffULL
1205 : cieID == 0xffffffff)) {
1206 // this is a CIE -- skip it
1207 } else {
1208 // this is a FDE
1209 uint64 initialLocationOffset = dataReader.Offset();
1210 // In .eh_frame the CIE offset is a relative back offset.
1211 if (ehFrame) {
1212 if (cieID > (uint64)lengthOffset) {
1213 TRACE_CFI("Invalid CIE offset: %" B_PRIu64 ", max "
1214 "possible: %" B_PRIu64 "\n", cieID, lengthOffset);
1215 break;
1216 }
1217 // convert to a section relative offset
1218 cieID = lengthOffset - cieID;
1219 }
1220
1221
1222 CfaContext context;
1223 CIEAugmentation cieAugmentation;
1224 // when using .eh_frame format, we need to parse the CIE's
1225 // augmentation up front in order to know how the FDE's addresses
1226 // will be represented
1227 DataReader cieReader;
1228 off_t cieRemaining;
1229 status_t error = _ParseCIEHeader(section, ehFrame, NULL,
1230 addressSize, isBigEndian, context,
1231 cieID, cieAugmentation, cieReader, cieRemaining);
1232 if (error != B_OK)
1233 return error;
1234 if (cieReader.HasOverflow())
1235 return B_BAD_DATA;
1236 if (cieRemaining < 0)
1237 return B_BAD_DATA;
1238
1239 target_addr_t initialLocation = cieAugmentation.ReadEncodedAddress(
1240 dataReader, fElfFile, section);
1241 target_addr_t addressRange = cieAugmentation.ReadEncodedAddress(
1242 dataReader, fElfFile, section, true);
1243
1244 if (dataReader.HasOverflow())
1245 return B_BAD_DATA;
1246
1247 if ((cieAugmentation.FDEAddressType()
1248 & CFI_ADDRESS_TYPE_PC_RELATIVE) != 0) {
1249 initialLocation += initialLocationOffset;
1250 }
1251
1252 // for unknown reasons, the debug frame sections generated by gcc
1253 // sometimes contain duplicates at different offsets within the
1254 // section. In such a case, simply skip the duplicates.
1255 FDELookupInfo* temp = _GetContainingFDEInfo(initialLocation,
1256 infos);
1257 if (temp == NULL) {
1258 FDELookupInfo* info = new(std::nothrow)FDELookupInfo(
1259 initialLocation, initialLocation + addressRange - 1,
1260 entryOffset, cieID, ehFrame);
1261 if (info == NULL)
1262 return B_NO_MEMORY;
1263
1264 ObjectDeleter<FDELookupInfo> infoDeleter(info);
1265 if (!infos.BinaryInsert(info, FDELookupInfo::CompareFDEInfos))
1266 return B_NO_MEMORY;
1267
1268 infoDeleter.Detach();
1269 }
1270 }
1271
1272 dataReader.SeekAbsolute(lengthOffset + length);
1273 }
1274
1275 return B_OK;
1276 }
1277
1278
1279 status_t
_ParseCompilationUnit(CompilationUnit * unit)1280 DwarfFile::_ParseCompilationUnit(CompilationUnit* unit)
1281 {
1282 AbbreviationTable* abbreviationTable;
1283 status_t error = _GetAbbreviationTable(unit->AbbreviationOffset(),
1284 abbreviationTable);
1285 if (error != B_OK)
1286 return error;
1287
1288 unit->SetAbbreviationTable(abbreviationTable);
1289
1290 DataReader dataReader(
1291 (const uint8*)fDebugInfoSection->Data() + unit->ContentOffset(),
1292 unit->ContentSize(), unit->AddressSize(), unit->IsBigEndian());
1293
1294 DebugInfoEntry* entry;
1295 bool endOfEntryList;
1296 error = _ParseDebugInfoEntry(dataReader, unit, abbreviationTable, entry,
1297 endOfEntryList);
1298 if (error != B_OK)
1299 return error;
1300
1301 DIECompileUnitBase* unitEntry = dynamic_cast<DIECompileUnitBase*>(entry);
1302 if (unitEntry == NULL) {
1303 WARNING("No compilation unit entry in .debug_info section.\n");
1304 return B_BAD_DATA;
1305 }
1306
1307 unit->SetUnitEntry(unitEntry);
1308
1309 TRACE_DIE_ONLY(
1310 TRACE_DIE("remaining bytes in unit: %" B_PRIdOFF "\n",
1311 dataReader.BytesRemaining());
1312 if (dataReader.HasData()) {
1313 TRACE_DIE(" ");
1314 while (dataReader.HasData())
1315 TRACE_DIE("%02x", dataReader.Read<uint8>(0));
1316 TRACE_DIE("\n");
1317 }
1318 )
1319 return B_OK;
1320 }
1321
1322
1323 status_t
_ParseTypeUnit(TypeUnit * unit)1324 DwarfFile::_ParseTypeUnit(TypeUnit* unit)
1325 {
1326 AbbreviationTable* abbreviationTable;
1327 status_t error = _GetAbbreviationTable(unit->AbbreviationOffset(),
1328 abbreviationTable);
1329 if (error != B_OK)
1330 return error;
1331
1332 unit->SetAbbreviationTable(abbreviationTable);
1333
1334 DataReader dataReader(
1335 (const uint8*)fDebugTypesSection->Data() + unit->ContentOffset(),
1336 unit->ContentSize(), unit->AddressSize(), unit->IsBigEndian());
1337
1338 DebugInfoEntry* entry;
1339 bool endOfEntryList;
1340 error = _ParseDebugInfoEntry(dataReader, unit, abbreviationTable, entry,
1341 endOfEntryList);
1342 if (error != B_OK)
1343 return error;
1344
1345 DIETypeUnit* unitEntry = dynamic_cast<DIETypeUnit*>(entry);
1346 if (unitEntry == NULL) {
1347 WARNING("No type unit entry in .debug_types section.\n");
1348 return B_BAD_DATA;
1349 }
1350
1351 unit->SetUnitEntry(unitEntry);
1352 DebugInfoEntry* typeEntry = unit->EntryForOffset(unit->TypeOffset());
1353 if (typeEntry == NULL) {
1354 WARNING("No type found for type unit %p at specified offset %"
1355 B_PRId64 ".\n", unit, unit->TypeOffset());
1356 return B_BAD_DATA;
1357 }
1358 unit->SetTypeEntry(typeEntry);
1359
1360 TRACE_DIE_ONLY(
1361 TRACE_DIE("remaining bytes in unit: %" B_PRIdOFF "\n",
1362 dataReader.BytesRemaining());
1363 if (dataReader.HasData()) {
1364 TRACE_DIE(" ");
1365 while (dataReader.HasData())
1366 TRACE_DIE("%02x", dataReader.Read<uint8>(0));
1367 TRACE_DIE("\n");
1368 }
1369 )
1370 return B_OK;
1371 }
1372
1373
1374 status_t
_ParseDebugInfoEntry(DataReader & dataReader,BaseUnit * unit,AbbreviationTable * abbreviationTable,DebugInfoEntry * & _entry,bool & _endOfEntryList,int level)1375 DwarfFile::_ParseDebugInfoEntry(DataReader& dataReader,
1376 BaseUnit* unit, AbbreviationTable* abbreviationTable,
1377 DebugInfoEntry*& _entry, bool& _endOfEntryList, int level)
1378 {
1379 off_t entryOffset = dataReader.Offset()
1380 + unit->RelativeContentOffset();
1381
1382 uint32 code = dataReader.ReadUnsignedLEB128(0);
1383 if (code == 0) {
1384 if (dataReader.HasOverflow()) {
1385 WARNING("Unexpected end of .debug_info section.\n");
1386 return B_BAD_DATA;
1387 }
1388 _entry = NULL;
1389 _endOfEntryList = true;
1390 return B_OK;
1391 }
1392
1393 // get the corresponding abbreviation entry
1394 AbbreviationEntry abbreviationEntry;
1395 if (!abbreviationTable->GetAbbreviationEntry(code, abbreviationEntry)) {
1396 WARNING("No abbreviation entry for code %" B_PRIx32 "\n", code);
1397 return B_BAD_DATA;
1398 }
1399
1400 DebugInfoEntry* entry;
1401 status_t error = fDebugInfoFactory.CreateDebugInfoEntry(
1402 abbreviationEntry.Tag(), entry);
1403 if (error != B_OK) {
1404 WARNING("Failed to generate entry for tag %" B_PRIu32 ", code %"
1405 B_PRIu32 "\n", abbreviationEntry.Tag(), code);
1406 return error;
1407 }
1408
1409 ObjectDeleter<DebugInfoEntry> entryDeleter(entry);
1410
1411 TRACE_DIE("%*sentry %p at %" B_PRIdOFF ": %" B_PRIu32 ", tag: %s (%"
1412 B_PRIu32 "), children: %d\n", level * 2, "", entry, entryOffset,
1413 abbreviationEntry.Code(), get_entry_tag_name(abbreviationEntry.Tag()),
1414 abbreviationEntry.Tag(), abbreviationEntry.HasChildren());
1415
1416 error = unit->AddDebugInfoEntry(entry, entryOffset);
1417
1418 if (error != B_OK)
1419 return error;
1420
1421 // parse the attributes (supply NULL entry to avoid adding them yet)
1422 error = _ParseEntryAttributes(dataReader, unit, NULL, abbreviationEntry);
1423 if (error != B_OK)
1424 return error;
1425
1426 // parse children, if the entry has any
1427 if (abbreviationEntry.HasChildren()) {
1428 while (true) {
1429 DebugInfoEntry* childEntry;
1430 bool endOfEntryList;
1431 status_t error = _ParseDebugInfoEntry(dataReader,
1432 unit, abbreviationTable, childEntry, endOfEntryList, level + 1);
1433 if (error != B_OK)
1434 return error;
1435
1436 // add the child to our entry
1437 if (childEntry != NULL) {
1438 if (entry != NULL) {
1439 error = entry->AddChild(childEntry);
1440 if (error == B_OK) {
1441 childEntry->SetParent(entry);
1442 } else if (error == ENTRY_NOT_HANDLED) {
1443 error = B_OK;
1444 TRACE_DIE("%*s -> child unhandled\n", level * 2, "");
1445 }
1446
1447 if (error != B_OK) {
1448 delete childEntry;
1449 return error;
1450 }
1451 } else
1452 delete childEntry;
1453 }
1454
1455 if (endOfEntryList)
1456 break;
1457 }
1458 }
1459
1460 entryDeleter.Detach();
1461 _entry = entry;
1462 _endOfEntryList = false;
1463 return B_OK;
1464 }
1465
1466
1467 status_t
_FinishUnit(BaseUnit * unit)1468 DwarfFile::_FinishUnit(BaseUnit* unit)
1469 {
1470 CompilationUnit* compilationUnit = dynamic_cast<CompilationUnit*>(unit);
1471 bool isTypeUnit = compilationUnit == NULL;
1472 TRACE_DIE("\nfinishing %s unit %p\n",
1473 isTypeUnit ? "type" : "compilation", unit);
1474
1475
1476 AbbreviationTable* abbreviationTable = unit->GetAbbreviationTable();
1477
1478 ElfSection* section = isTypeUnit
1479 ? fDebugTypesSection : fDebugInfoSection;
1480 DataReader dataReader(
1481 (const uint8*)section->Data() + unit->HeaderOffset(),
1482 unit->TotalSize(), unit->AddressSize(), unit->IsBigEndian());
1483
1484 DebugInfoEntryInitInfo entryInitInfo;
1485
1486 int entryCount = unit->CountEntries();
1487 for (int i = 0; i < entryCount; i++) {
1488 // get the entry
1489 DebugInfoEntry* entry;
1490 off_t offset;
1491 unit->GetEntryAt(i, entry, offset);
1492
1493 TRACE_DIE("entry %p at %" B_PRIdOFF "\n", entry, offset);
1494
1495 // seek the reader to the entry
1496 dataReader.SeekAbsolute(offset);
1497
1498 // read the entry code
1499 uint32 code = dataReader.ReadUnsignedLEB128(0);
1500
1501 // get the respective abbreviation entry
1502 AbbreviationEntry abbreviationEntry;
1503 abbreviationTable->GetAbbreviationEntry(code, abbreviationEntry);
1504
1505 // initialization before setting the attributes
1506 status_t error = entry->InitAfterHierarchy(entryInitInfo);
1507 if (error != B_OK) {
1508 WARNING("Init after hierarchy failed!\n");
1509 return error;
1510 }
1511
1512 // parse the attributes -- this time pass the entry, so that the
1513 // attribute get set on it
1514 error = _ParseEntryAttributes(dataReader, unit, entry,
1515 abbreviationEntry);
1516 if (error != B_OK)
1517 return error;
1518
1519 // initialization after setting the attributes
1520 error = entry->InitAfterAttributes(entryInitInfo);
1521 if (error != B_OK) {
1522 WARNING("Init after attributes failed!\n");
1523 return error;
1524 }
1525 }
1526
1527 // set the compilation unit's source language
1528 unit->SetSourceLanguage(entryInitInfo.languageInfo);
1529
1530 if (isTypeUnit)
1531 return B_OK;
1532
1533 // resolve the compilation unit's address range list
1534 if (TargetAddressRangeList* ranges = ResolveRangeList(compilationUnit,
1535 compilationUnit->UnitEntry()->AddressRangesOffset())) {
1536 compilationUnit->SetAddressRanges(ranges);
1537 ranges->ReleaseReference();
1538 }
1539
1540 // add compilation dir to directory list
1541 const char* compilationDir = compilationUnit->UnitEntry()
1542 ->CompilationDir();
1543 if (!compilationUnit->AddDirectory(compilationDir != NULL
1544 ? compilationDir : ".")) {
1545 return B_NO_MEMORY;
1546 }
1547
1548 // parse line info header
1549 if (fDebugLineSection != NULL)
1550 _ParseLineInfo(compilationUnit);
1551
1552 return B_OK;
1553 }
1554
1555
1556 status_t
_ReadStringIndirect(BaseUnit * unit,uint64 index,const char * & value) const1557 DwarfFile::_ReadStringIndirect(BaseUnit* unit, uint64 index, const char*& value) const
1558 {
1559 if (fDebugStrOffsetsSection == NULL) {
1560 WARNING("Invalid DW_FORM_strx*: no debug_str_offsets section!\n");
1561 return B_BAD_DATA;
1562 }
1563
1564 uint64 strOffsetsBase = unit->IsDwarf64() ? 16 : 8;
1565 uint64 offsetSize = unit->IsDwarf64() ? 8 : 4;
1566
1567 if (strOffsetsBase + index * offsetSize >= fDebugStrOffsetsSection->Size()) {
1568 WARNING("Invalid DW_FORM_strx* index: %" B_PRIu64 "\n", index);
1569 return B_BAD_DATA;
1570 }
1571
1572 const char *strOffsets = (const char*)fDebugStrOffsetsSection->Data() + strOffsetsBase;
1573 uint64 offset = unit->IsDwarf64()
1574 ? ((uint64*)strOffsets)[index]
1575 : ((uint32*)strOffsets)[index];
1576
1577 if (offset >= fDebugStringSection->Size()) {
1578 WARNING("Invalid DW_FORM_strx* offset: %" B_PRIu64 "\n", offset);
1579 return B_BAD_DATA;
1580 }
1581
1582 value = (const char*)fDebugStringSection->Data() + offset;
1583 return B_OK;
1584 }
1585
1586
1587 status_t
_ReadAddressIndirect(BaseUnit * unit,uint64 index,uint64 & value) const1588 DwarfFile::_ReadAddressIndirect(BaseUnit* unit, uint64 index, uint64& value) const
1589 {
1590 if (fDebugAddressSection == NULL) {
1591 WARNING("Invalid DW_FORM_addrx*: no debug_addr section!\n");
1592 return B_BAD_DATA;
1593 }
1594
1595 uint64 addrBase = unit->IsDwarf64() ? 16 : 8;
1596
1597 if (addrBase + index * unit->AddressSize() >= fDebugAddressSection->Size()) {
1598 WARNING("Invalid DW_FORM_addrx* index: %" B_PRIu64 "\n", index);
1599 return B_BAD_DATA;
1600 }
1601
1602 const char *addrPtr = (const char*)fDebugAddressSection->Data()
1603 + addrBase + index * unit->AddressSize();
1604
1605 if (unit->AddressSize() == 8)
1606 value = *(uint64*)addrPtr;
1607 else
1608 value = *(uint32*)addrPtr;
1609
1610 return B_OK;
1611 }
1612
1613
1614 status_t
_ParseEntryAttributes(DataReader & dataReader,BaseUnit * unit,DebugInfoEntry * entry,AbbreviationEntry & abbreviationEntry)1615 DwarfFile::_ParseEntryAttributes(DataReader& dataReader,
1616 BaseUnit* unit, DebugInfoEntry* entry, AbbreviationEntry& abbreviationEntry)
1617 {
1618 uint32 attributeName;
1619 uint32 attributeForm;
1620 int32 attributeImplicitConst = 0;
1621 while (abbreviationEntry.GetNextAttribute(attributeName,
1622 attributeForm, attributeImplicitConst)) {
1623 // resolve attribute form indirection
1624 if (attributeForm == DW_FORM_indirect)
1625 attributeForm = dataReader.ReadUnsignedLEB128(0);
1626
1627 // prepare an AttributeValue
1628 AttributeValue attributeValue;
1629 attributeValue.attributeForm = attributeForm;
1630 bool isSigned = false;
1631
1632 // Read the attribute value according to the attribute's form. For
1633 // the forms that don't map to a single attribute class only or
1634 // those that need additional processing, we read a temporary value
1635 // first.
1636 uint64 value = 0;
1637 off_t blockLength = 0;
1638 off_t valueOffset = dataReader.Offset() + unit->ContentOffset();
1639 uint8 refType = dwarf_reference_type_local;
1640
1641 switch (attributeForm) {
1642 case DW_FORM_addr:
1643 value = dataReader.ReadAddress(0);
1644 break;
1645 case DW_FORM_block2:
1646 blockLength = dataReader.Read<uint16>(0);
1647 break;
1648 case DW_FORM_block4:
1649 blockLength = dataReader.Read<uint32>(0);
1650 break;
1651 case DW_FORM_data2:
1652 value = dataReader.Read<uint16>(0);
1653 break;
1654 case DW_FORM_data4:
1655 value = dataReader.Read<uint32>(0);
1656 break;
1657 case DW_FORM_data8:
1658 value = dataReader.Read<uint64>(0);
1659 break;
1660 case DW_FORM_string:
1661 attributeValue.SetToString(dataReader.ReadString());
1662 break;
1663 case DW_FORM_block:
1664 case DW_FORM_exprloc:
1665 blockLength = dataReader.ReadUnsignedLEB128(0);
1666 break;
1667 case DW_FORM_block1:
1668 blockLength = dataReader.Read<uint8>(0);
1669 break;
1670 case DW_FORM_data1:
1671 value = dataReader.Read<uint8>(0);
1672 break;
1673 case DW_FORM_flag:
1674 attributeValue.SetToFlag(dataReader.Read<uint8>(0) != 0);
1675 break;
1676 case DW_FORM_sdata:
1677 value = dataReader.ReadSignedLEB128(0);
1678 isSigned = true;
1679 break;
1680 case DW_FORM_strp:
1681 {
1682 if (fDebugStringSection != NULL) {
1683 uint64 offset = unit->IsDwarf64()
1684 ? dataReader.Read<uint64>(0)
1685 : dataReader.Read<uint32>(0);
1686 if (offset >= fDebugStringSection->Size()) {
1687 WARNING("Invalid DW_FORM_strp offset: %" B_PRIu64 "\n",
1688 offset);
1689 return B_BAD_DATA;
1690 }
1691 attributeValue.SetToString(
1692 (const char*)fDebugStringSection->Data() + offset);
1693 } else {
1694 WARNING("Invalid DW_FORM_strp: no string section!\n");
1695 return B_BAD_DATA;
1696 }
1697 break;
1698 }
1699 case DW_FORM_udata:
1700 value = dataReader.ReadUnsignedLEB128(0);
1701 break;
1702 case DW_FORM_ref_addr:
1703 value = unit->IsDwarf64()
1704 ? dataReader.Read<uint64>(0)
1705 : (uint64)dataReader.Read<uint32>(0);
1706 refType = dwarf_reference_type_global;
1707 break;
1708 case DW_FORM_ref1:
1709 value = dataReader.Read<uint8>(0);
1710 break;
1711 case DW_FORM_ref2:
1712 value = dataReader.Read<uint16>(0);
1713 break;
1714 case DW_FORM_ref4:
1715 value = dataReader.Read<uint32>(0);
1716 break;
1717 case DW_FORM_ref8:
1718 value = dataReader.Read<uint64>(0);
1719 break;
1720 case DW_FORM_ref_udata:
1721 value = dataReader.ReadUnsignedLEB128(0);
1722 break;
1723 case DW_FORM_flag_present:
1724 attributeValue.SetToFlag(true);
1725 break;
1726 case DW_FORM_strx:
1727 {
1728 uint64 index = dataReader.ReadUnsignedLEB128(0);
1729 const char* strValue;
1730 status_t res = _ReadStringIndirect(unit, index, strValue);
1731 if (res != B_OK)
1732 return res;
1733 attributeValue.SetToString(strValue);
1734 break;
1735 }
1736 case DW_FORM_addrx:
1737 {
1738 uint64 index = dataReader.ReadUnsignedLEB128(0);
1739 status_t res = _ReadAddressIndirect(unit, index, value);
1740 if (res != B_OK)
1741 return res;
1742 break;
1743 }
1744 case DW_FORM_line_strp:
1745 {
1746 if (fDebugLineStrSection != NULL) {
1747 uint64 offset = unit->IsDwarf64()
1748 ? dataReader.Read<uint64>(0)
1749 : dataReader.Read<uint32>(0);
1750 if (offset >= fDebugLineStrSection->Size()) {
1751 WARNING("Invalid DW_FORM_line_strp offset: %" B_PRIu64 "\n",
1752 offset);
1753 return B_BAD_DATA;
1754 }
1755 attributeValue.SetToString(
1756 (const char*)fDebugLineStrSection->Data() + offset);
1757 } else {
1758 WARNING("Invalid DW_FORM_line_strp: no debug_line_str section!\n");
1759 return B_BAD_DATA;
1760 }
1761 break;
1762 }
1763 case DW_FORM_ref_sig8:
1764 fTypesSectionRequired = true;
1765 value = dataReader.Read<uint64>(0);
1766 refType = dwarf_reference_type_signature;
1767 break;
1768 case DW_FORM_implicit_const:
1769 value = attributeImplicitConst;
1770 break;
1771 case DW_FORM_sec_offset:
1772 value = unit->IsDwarf64()
1773 ? dataReader.Read<uint64>(0)
1774 : (uint64)dataReader.Read<uint32>(0);
1775 break;
1776 case DW_FORM_strx1:
1777 case DW_FORM_strx2:
1778 case DW_FORM_strx3:
1779 case DW_FORM_strx4:
1780 {
1781 size_t numBytes = attributeForm - DW_FORM_strx1 + 1;
1782 uint64 index = dataReader.ReadUInt(numBytes, 0);
1783 const char* strValue;
1784 status_t res = _ReadStringIndirect(unit, index, strValue);
1785 if (res != B_OK)
1786 return res;
1787 attributeValue.SetToString(strValue);
1788 break;
1789 }
1790 case DW_FORM_addrx1:
1791 case DW_FORM_addrx2:
1792 case DW_FORM_addrx3:
1793 case DW_FORM_addrx4:
1794 {
1795 size_t numBytes = attributeForm - DW_FORM_addrx1 + 1;
1796 uint64 index = dataReader.ReadUInt(numBytes, 0);
1797 status_t res = _ReadAddressIndirect(unit, index, value);
1798 if (res != B_OK)
1799 return res;
1800 break;
1801 }
1802 case DW_FORM_indirect:
1803 default:
1804 WARNING("Unsupported attribute form: %" B_PRIu32 "\n",
1805 attributeForm);
1806 return B_BAD_DATA;
1807 }
1808
1809 // get the attribute class -- skip the attribute, if we can't handle
1810 // it
1811 uint8 attributeClass = get_attribute_class(attributeName,
1812 attributeForm);
1813
1814 if (attributeClass == ATTRIBUTE_CLASS_UNKNOWN) {
1815 TRACE_DIE("skipping attribute with unrecognized class: %s (%#"
1816 B_PRIx32 ") %s (%#" B_PRIx32 ")\n",
1817 get_attribute_name_name(attributeName), attributeName,
1818 get_attribute_form_name(attributeForm), attributeForm);
1819 continue;
1820 }
1821
1822 // set the attribute value according to the attribute's class
1823 switch (attributeClass) {
1824 case ATTRIBUTE_CLASS_ADDRESS:
1825 attributeValue.SetToAddress(value);
1826 break;
1827 case ATTRIBUTE_CLASS_ADDRPTR:
1828 attributeValue.SetToAddrPtr(value);
1829 break;
1830 case ATTRIBUTE_CLASS_BLOCK:
1831 attributeValue.SetToBlock(dataReader.Data(), blockLength);
1832 dataReader.Skip(blockLength);
1833 break;
1834 case ATTRIBUTE_CLASS_CONSTANT:
1835 attributeValue.SetToConstant(value, isSigned);
1836 break;
1837 case ATTRIBUTE_CLASS_LINEPTR:
1838 attributeValue.SetToLinePointer(value);
1839 break;
1840 case ATTRIBUTE_CLASS_LOCLIST:
1841 attributeValue.SetToLocationList(value);
1842 break;
1843 case ATTRIBUTE_CLASS_LOCLISTPTR:
1844 attributeValue.SetToLocationListPointer(value);
1845 break;
1846 case ATTRIBUTE_CLASS_MACPTR:
1847 attributeValue.SetToMacroPointer(value);
1848 break;
1849 case ATTRIBUTE_CLASS_RANGELIST:
1850 attributeValue.SetToRangeList(value);
1851 break;
1852 case ATTRIBUTE_CLASS_RANGELISTPTR:
1853 attributeValue.SetToRangeListPointer(value);
1854 break;
1855 case ATTRIBUTE_CLASS_REFERENCE:
1856 if (entry != NULL) {
1857 attributeValue.SetToReference(_ResolveReference(
1858 unit, value, refType));
1859 if (attributeValue.reference == NULL) {
1860 // gcc 2 apparently somtimes produces DW_AT_sibling
1861 // attributes pointing to the end of the sibling list.
1862 // Just ignore those.
1863 if (attributeName == DW_AT_sibling)
1864 continue;
1865
1866 WARNING("Failed to resolve reference on entry %p: "
1867 "(%#" B_PRIx64 ") %s (%#" B_PRIx32 ") %s "
1868 "(%#" B_PRIx32 "): value: %#" B_PRIx64 "\n",
1869 entry,
1870 valueOffset,
1871 get_attribute_name_name(attributeName),
1872 attributeName,
1873 get_attribute_form_name(attributeForm),
1874 attributeForm, value);
1875 return B_ENTRY_NOT_FOUND;
1876 }
1877 }
1878 break;
1879 case ATTRIBUTE_CLASS_FLAG:
1880 case ATTRIBUTE_CLASS_STRING:
1881 // already set
1882 break;
1883 case ATTRIBUTE_CLASS_STROFFSETSPTR:
1884 attributeValue.SetToStrOffsetsPtr(value);
1885 break;
1886 }
1887
1888 if (dataReader.HasOverflow()) {
1889 WARNING("Unexpected end of .debug_info section.\n");
1890 return B_BAD_DATA;
1891 }
1892
1893 TRACE_DIE_ONLY(
1894 char buffer[1024];
1895 TRACE_DIE(" attr (%#" B_PRIx64 ") %s %s (%d): %s\n",
1896 valueOffset,
1897 get_attribute_name_name(attributeName),
1898 get_attribute_form_name(attributeForm), attributeClass,
1899 attributeValue.ToString(buffer, sizeof(buffer)));
1900 )
1901
1902 // add the attribute
1903 if (entry != NULL) {
1904 DebugInfoEntrySetter attributeSetter
1905 = get_attribute_name_setter(attributeName);
1906 if (attributeSetter != 0) {
1907 status_t error = (entry->*attributeSetter)(attributeName,
1908 attributeValue);
1909
1910 if (error == ATTRIBUTE_NOT_HANDLED) {
1911 error = B_OK;
1912 TRACE_DIE(" -> unhandled\n");
1913 }
1914
1915 if (error != B_OK) {
1916 WARNING("Failed to set attribute: name: %s, form: %s: %s\n",
1917 get_attribute_name_name(attributeName),
1918 get_attribute_form_name(attributeForm),
1919 strerror(error));
1920 }
1921 } else
1922 TRACE_DIE(" -> no attribute setter!\n");
1923 }
1924 }
1925
1926 return B_OK;
1927 }
1928
1929
1930 status_t
_ParseLineInfoFormatString(CompilationUnit * unit,DataReader & dataReader,uint64 format,const char * & value)1931 DwarfFile::_ParseLineInfoFormatString(CompilationUnit* unit, DataReader &dataReader,
1932 uint64 format, const char*& value)
1933 {
1934 switch (format) {
1935 case DW_FORM_string:
1936 value = dataReader.ReadString();
1937 break;
1938 case DW_FORM_line_strp:
1939 {
1940 if (fDebugLineStrSection == NULL) {
1941 WARNING("Invalid DW_FORM_line_strp: no line_str section!\n");
1942 return B_BAD_DATA;
1943 }
1944
1945 target_addr_t offset = unit->IsDwarf64()
1946 ? dataReader.Read<uint64>(0)
1947 : dataReader.Read<uint32>(0);
1948 if (offset > fDebugLineStrSection->Size()) {
1949 WARNING("Invalid DW_FORM_line_strp offset: %" B_PRIu64 "\n",
1950 offset);
1951 return B_BAD_DATA;
1952 }
1953
1954 value = (const char*)fDebugLineStrSection->Data() + offset;
1955 break;
1956 }
1957 case DW_FORM_strp:
1958 {
1959 if (fDebugStringSection == NULL) {
1960 WARNING("Invalid DW_FORM_strp: no string section!\n");
1961 return B_BAD_DATA;
1962 }
1963
1964 target_addr_t offset = unit->IsDwarf64()
1965 ? dataReader.Read<uint64>(0)
1966 : dataReader.Read<uint32>(0);
1967 if (offset > fDebugStringSection->Size()) {
1968 WARNING("Invalid DW_FORM_strp offset: %" B_PRIu64 "\n",
1969 offset);
1970 return B_BAD_DATA;
1971 }
1972
1973 value = (const char*)fDebugStringSection->Data() + offset;
1974 break;
1975 }
1976 case DW_FORM_strp_sup:
1977 return B_UNSUPPORTED;
1978 break;
1979 default:
1980 WARNING("DwarfFile::_ParseLineInfoFormatString(\"%s\"): unsupported "
1981 "field type %" PRIu64 "\n", fName, format);
1982 return B_BAD_DATA;
1983 }
1984
1985 return B_OK;
1986 }
1987
1988
1989 status_t
_ParseLineInfoFormatUint(CompilationUnit * unit,DataReader & dataReader,uint64 format,uint64 & value)1990 DwarfFile::_ParseLineInfoFormatUint(CompilationUnit* unit, DataReader &dataReader,
1991 uint64 format, uint64 &value)
1992 {
1993 switch (format)
1994 {
1995 case DW_FORM_data1:
1996 value = dataReader.Read<uint8>(0);
1997 break;
1998 case DW_FORM_data2:
1999 value = dataReader.Read<uint16>(0);
2000 break;
2001 case DW_FORM_data4:
2002 value = dataReader.Read<uint32>(0);
2003 break;
2004 case DW_FORM_data8:
2005 value = dataReader.Read<uint64>(0);
2006 break;
2007 case DW_FORM_udata:
2008 value = dataReader.ReadUnsignedLEB128(0);
2009 break;
2010 default:
2011 WARNING("DwarfFile::_ParseLineInfoFormatUint(\"%s\"): unsupported "
2012 "field type %" PRIu64 "\n", fName, format);
2013 return B_BAD_DATA;
2014 }
2015
2016 return B_OK;
2017 }
2018
2019
2020 status_t
_ParseLineInfo(CompilationUnit * unit)2021 DwarfFile::_ParseLineInfo(CompilationUnit* unit)
2022 {
2023 off_t offset = unit->UnitEntry()->StatementListOffset();
2024
2025 TRACE_LINES("DwarfFile::_ParseLineInfo(%p), offset: %" B_PRIdOFF "\n", unit,
2026 offset);
2027
2028 DataReader dataReader((uint8*)fDebugLineSection->Data() + offset,
2029 fDebugLineSection->Size() - offset, unit->AddressSize(), unit->IsBigEndian());
2030
2031 // unit length
2032 bool dwarf64;
2033 uint64 unitLength = dataReader.ReadInitialLength(dwarf64);
2034 if (unitLength > (uint64)dataReader.BytesRemaining())
2035 return B_BAD_DATA;
2036 off_t unitOffset = dataReader.Offset();
2037
2038 // version (uhalf)
2039 uint16 version = dataReader.Read<uint16>(0);
2040
2041 if (version < 2 || version > 5) {
2042 WARNING("DwarfFile::_ParseLineInfo(\"%s\"): unsupported "
2043 "version %d\n", fName, version);
2044 return B_UNSUPPORTED;
2045 }
2046
2047 uint8 addressSize = unit->AddressSize();
2048 uint8 segmentSelectorSize = 0;
2049
2050 if (version >= 5) {
2051 addressSize = dataReader.Read<uint8>(0);
2052 if (addressSize != 4 && addressSize != 8) {
2053 WARNING("DwarfFile::_ParseLineInfo(\"%s\"): unsupported "
2054 "addressSize %d\n", fName, addressSize);
2055 return B_BAD_DATA;
2056 }
2057
2058 segmentSelectorSize = dataReader.Read<uint8>(0);
2059 if (segmentSelectorSize != 0) {
2060 WARNING("DwarfFile::_ParseLineInfo(\"%s\"): unsupported "
2061 "segmentSelectorSize %d\n", fName, segmentSelectorSize);
2062 return B_BAD_DATA;
2063 }
2064 }
2065
2066 // header_length (4/8)
2067 uint64 headerLength = dwarf64
2068 ? dataReader.Read<uint64>(0) : (uint64)dataReader.Read<uint32>(0);
2069 off_t headerOffset = dataReader.Offset();
2070
2071 if ((uint64)dataReader.BytesRemaining() < headerLength)
2072 return B_BAD_DATA;
2073
2074 // minimum instruction length
2075 uint8 minInstructionLength = dataReader.Read<uint8>(0);
2076
2077 uint8 maxOpsPerInstruction;
2078 if (version >= 4)
2079 maxOpsPerInstruction = dataReader.Read<uint8>(0);
2080 else
2081 maxOpsPerInstruction = 1;
2082
2083 if (maxOpsPerInstruction != 1) {
2084 WARNING("DwarfFile::_ParseLineInfo(\"%s\"): unsupported "
2085 "maxOpsPerInstruction %u\n", fName, maxOpsPerInstruction);
2086 return B_UNSUPPORTED;
2087 }
2088
2089 // default is statement
2090 bool defaultIsStatement = dataReader.Read<uint8>(0) != 0;
2091
2092 // line_base (sbyte)
2093 int8 lineBase = (int8)dataReader.Read<uint8>(0);
2094
2095 // line_range (ubyte)
2096 uint8 lineRange = dataReader.Read<uint8>(0);
2097
2098 // opcode_base (ubyte)
2099 uint8 opcodeBase = dataReader.Read<uint8>(0);
2100
2101 // standard_opcode_lengths (ubyte[])
2102 const uint8* standardOpcodeLengths = (const uint8*)dataReader.Data();
2103 dataReader.Skip(opcodeBase - 1);
2104
2105 if (dataReader.HasOverflow())
2106 return B_BAD_DATA;
2107
2108 TRACE_LINES(" unitLength: %" B_PRIu64 "\n", unitLength);
2109 TRACE_LINES(" version: %u\n", version);
2110 if (version >= 5) {
2111 TRACE_LINES(" addressSize: %u\n", addressSize);
2112 TRACE_LINES(" segmentSelectorSize: %u\n", segmentSelectorSize);
2113 }
2114 TRACE_LINES(" headerLength: %" B_PRIu64 "\n", headerLength);
2115 TRACE_LINES(" minInstructionLength: %u\n", minInstructionLength);
2116 if (version >= 4)
2117 TRACE_LINES(" maxOpsPerInstruction: %u\n", maxOpsPerInstruction);
2118 TRACE_LINES(" defaultIsStatement: %d\n", defaultIsStatement);
2119 TRACE_LINES(" lineBase: %d\n", lineBase);
2120 TRACE_LINES(" lineRange: %u\n", lineRange);
2121 TRACE_LINES(" opcodeBase: %u\n", opcodeBase);
2122
2123 if (version >= 5) {
2124 uint8 dirEntryFormatCount = dataReader.Read<uint8>(0);
2125 TRACE_LINES(" dirEntryFormatCount: %u\n", dirEntryFormatCount);
2126
2127 off_t dirEntryFormatOffset = dataReader.Offset();
2128 for (unsigned int i = 0; i < dirEntryFormatCount; i++) {
2129 TRACE_LINES_ONLY(uint64 content =)
2130 dataReader.ReadUnsignedLEB128(0);
2131 TRACE_LINES_ONLY(uint64 format =)
2132 dataReader.ReadUnsignedLEB128(0);
2133
2134 TRACE_LINES(" content: %" B_PRIu64 "\n", content);
2135 TRACE_LINES(" format: %" B_PRIu64 "\n", format);
2136 }
2137 off_t dirEntryFormatLength = dataReader.Offset() - dirEntryFormatOffset;
2138 DataReader dirEntryFormatReader = dataReader.RestrictedReader(-dirEntryFormatLength,
2139 dirEntryFormatLength);
2140
2141 uint8 dirCount = dataReader.Read<uint8>(0);
2142 TRACE_LINES(" dirCount: %u\n", dirCount);
2143
2144 for (unsigned int i = 0; i < dirCount; i++) {
2145 dirEntryFormatReader.SeekAbsolute(0);
2146 for (unsigned int j = 0; j < dirEntryFormatCount; j++) {
2147 uint64 content = dirEntryFormatReader.ReadUnsignedLEB128(0);
2148 uint64 format = dirEntryFormatReader.ReadUnsignedLEB128(0);
2149 if (content != DW_LNCT_path) {
2150 WARNING("DwarfFile::_ParseLineInfo(\"%s\"): unsupported "
2151 "field in dirs %" PRIu64 "\n", fName, content);
2152 return B_UNSUPPORTED;
2153 }
2154
2155 const char* directory;
2156 status_t res = _ParseLineInfoFormatString(unit, dataReader, format, directory);
2157 if (res != B_OK)
2158 return res;
2159 TRACE_LINES(" \"%s\"\n", directory);
2160
2161 if (!unit->AddDirectory(directory))
2162 return B_NO_MEMORY;
2163
2164 }
2165 }
2166
2167 uint8 fileNameEntryFormatCount = dataReader.Read<uint8>(0);
2168 TRACE_LINES(" fileNameFormatCount: %u\n", fileNameEntryFormatCount);
2169
2170 off_t fileNameEntryFormatOffset = dataReader.Offset();
2171 for (unsigned int i = 0; i < fileNameEntryFormatCount; i++) {
2172 TRACE_LINES_ONLY(uint64 content =)
2173 dataReader.ReadUnsignedLEB128(0);
2174 TRACE_LINES_ONLY(uint64 format =)
2175 dataReader.ReadUnsignedLEB128(0);
2176
2177 TRACE_LINES(" content: %" B_PRIu64 "\n", content);
2178 TRACE_LINES(" format: %" B_PRIu64 "\n", format);
2179 }
2180 off_t fileNameEntryFormatLength = dataReader.Offset() - fileNameEntryFormatOffset;
2181 DataReader fileNameEntryFormatReader = dataReader.RestrictedReader(-fileNameEntryFormatLength,
2182 fileNameEntryFormatLength);
2183
2184 uint8 fileNameCount = dataReader.Read<uint8>(0);
2185 TRACE_LINES(" fileNameCount: %u\n", dirCount);
2186
2187 for (unsigned int i = 0; i < fileNameCount; i++) {
2188 const char* fileName = NULL;
2189 uint64 dirIndex = 0xffffffffffffffffull;
2190 uint64 modificationTime = 0;
2191 uint64 fileLength = 0;
2192
2193 fileNameEntryFormatReader.SeekAbsolute(0);
2194 for (unsigned int j = 0; j < fileNameEntryFormatCount; j++) {
2195
2196 uint64 content = fileNameEntryFormatReader.ReadUnsignedLEB128(0);
2197 uint64 format = fileNameEntryFormatReader.ReadUnsignedLEB128(0);
2198 status_t res;
2199 switch (content) {
2200 case DW_LNCT_path:
2201 res = _ParseLineInfoFormatString(unit, dataReader,
2202 format, fileName);
2203 if (res != B_OK)
2204 return res;
2205 break;
2206 case DW_LNCT_directory_index:
2207 res = _ParseLineInfoFormatUint(unit, dataReader,
2208 format, dirIndex);
2209 if (res != B_OK)
2210 return res;
2211 break;
2212 case DW_LNCT_timestamp:
2213 res = _ParseLineInfoFormatUint(unit, dataReader,
2214 format, modificationTime);
2215 if (res != B_OK)
2216 return res;
2217 break;
2218 case DW_LNCT_size:
2219 res = _ParseLineInfoFormatUint(unit, dataReader,
2220 format, fileLength);
2221 if (res != B_OK)
2222 return res;
2223 break;
2224 case DW_LNCT_MD5:
2225 if (format != DW_FORM_data16)
2226 return B_BAD_DATA;
2227
2228 dataReader.Skip(16);
2229 break;
2230 default:
2231 WARNING("DwarfFile::_ParseLineInfo(\"%s\"): unsupported "
2232 "field in files %" PRIu64 "\n",
2233 fName, content);
2234 return B_UNSUPPORTED;
2235 }
2236 }
2237
2238 if ((fileName != NULL) && (dirIndex != 0xffffffffffffffffull)) {
2239 TRACE_LINES(" \"%s\", dir index: %" B_PRIu64 "\n",
2240 fileName, dirIndex);
2241
2242 if (!unit->AddFile(fileName, dirIndex))
2243 return B_NO_MEMORY;
2244 }
2245 }
2246 } else {
2247 // include directories
2248 TRACE_LINES(" include directories:\n");
2249 while (const char* directory = dataReader.ReadString()) {
2250 if (*directory == '\0')
2251 break;
2252 TRACE_LINES(" \"%s\"\n", directory);
2253
2254 if (!unit->AddDirectory(directory))
2255 return B_NO_MEMORY;
2256 }
2257
2258 // file names
2259 TRACE_LINES(" files:\n");
2260 while (const char* file = dataReader.ReadString()) {
2261 if (*file == '\0')
2262 break;
2263 uint64 dirIndex = dataReader.ReadUnsignedLEB128(0);
2264 TRACE_LINES_ONLY(uint64 modificationTime =)
2265 dataReader.ReadUnsignedLEB128(0);
2266 TRACE_LINES_ONLY(uint64 fileLength =)
2267 dataReader.ReadUnsignedLEB128(0);
2268
2269 if (dataReader.HasOverflow())
2270 return B_BAD_DATA;
2271
2272 TRACE_LINES(" \"%s\", dir index: %" B_PRIu64 ", mtime: %" B_PRIu64
2273 ", length: %" B_PRIu64 "\n", file, dirIndex, modificationTime,
2274 fileLength);
2275
2276 if (!unit->AddFile(file, dirIndex))
2277 return B_NO_MEMORY;
2278 }
2279 }
2280
2281 off_t readerOffset = dataReader.Offset();
2282 if ((uint64)readerOffset > readerOffset + headerLength)
2283 return B_BAD_DATA;
2284 off_t offsetToProgram = headerOffset + headerLength - readerOffset;
2285
2286 const uint8* program = (uint8*)dataReader.Data() + offsetToProgram;
2287 size_t programSize = unitLength - (readerOffset - unitOffset);
2288
2289 return unit->GetLineNumberProgram().Init(program, programSize,
2290 minInstructionLength, defaultIsStatement, lineBase, lineRange,
2291 opcodeBase, standardOpcodeLengths);
2292 }
2293
2294
2295 status_t
_UnwindCallFrame(CompilationUnit * unit,uint8 addressSize,bool isBigEndian,DIESubprogram * subprogramEntry,target_addr_t location,const FDELookupInfo * info,const DwarfTargetInterface * inputInterface,DwarfTargetInterface * outputInterface,target_addr_t & _framePointer)2296 DwarfFile::_UnwindCallFrame(CompilationUnit* unit, uint8 addressSize, bool isBigEndian,
2297 DIESubprogram* subprogramEntry, target_addr_t location,
2298 const FDELookupInfo* info, const DwarfTargetInterface* inputInterface,
2299 DwarfTargetInterface* outputInterface, target_addr_t& _framePointer)
2300 {
2301 ElfSection* currentFrameSection = (info->ehFrame)
2302 ? fEHFrameSection : fDebugFrameSection;
2303
2304 TRACE_CFI("DwarfFile::_UnwindCallFrame(%#" B_PRIx64 ")\n", location);
2305
2306 DataReader dataReader((uint8*)currentFrameSection->Data(),
2307 currentFrameSection->Size(),
2308 unit != NULL ? unit->AddressSize() : addressSize,
2309 unit != NULL ? unit->IsBigEndian() : isBigEndian);
2310 dataReader.SeekAbsolute(info->fdeOffset);
2311
2312 bool dwarf64;
2313 uint64 length = dataReader.ReadInitialLength(dwarf64);
2314 uint64 lengthOffset = dataReader.Offset();
2315
2316 CfaContext context;
2317 CIEAugmentation cieAugmentation;
2318 // when using .eh_frame format, we need to parse the CIE's
2319 // augmentation up front in order to know how the FDE's addresses
2320 // will be represented
2321 DataReader cieReader;
2322 off_t cieRemaining;
2323 status_t error = _ParseCIEHeader(currentFrameSection,
2324 info->ehFrame, unit, addressSize, isBigEndian, context, info->cieOffset,
2325 cieAugmentation, cieReader, cieRemaining);
2326 if (error != B_OK)
2327 return error;
2328 if (cieReader.HasOverflow())
2329 return B_BAD_DATA;
2330 if (cieRemaining < 0)
2331 return B_BAD_DATA;
2332
2333 // skip CIE ID, initial offset and range, since we already know those
2334 // from FDELookupInfo.
2335 dwarf64 ? dataReader.Read<uint64>(0) : dataReader.Read<uint32>(0);
2336 cieAugmentation.ReadEncodedAddress(dataReader, fElfFile,
2337 currentFrameSection);
2338 cieAugmentation.ReadEncodedAddress(dataReader, fElfFile,
2339 currentFrameSection, true);
2340
2341 TRACE_CFI(" found fde: length: %" B_PRIu64 " (%" B_PRIdOFF
2342 "), CIE offset: %#" B_PRIx64 ", location: %#" B_PRIx64 ", "
2343 "range: %#" B_PRIx64 "\n", length, dataReader.BytesRemaining(),
2344 info->cieOffset, info->start, info->end - info->start);
2345
2346 context.SetLocation(location, info->start);
2347 uint32 registerCount = outputInterface->CountRegisters();
2348 error = context.Init(registerCount);
2349 if (error != B_OK)
2350 return error;
2351
2352 error = outputInterface->InitRegisterRules(context);
2353 if (error != B_OK)
2354 return error;
2355
2356 // process the CIE's frame info instructions
2357 cieReader = cieReader.RestrictedReader(cieRemaining);
2358 error = _ParseFrameInfoInstructions(unit, context,
2359 cieReader, cieAugmentation);
2360 if (error != B_OK)
2361 return error;
2362
2363 // read the FDE augmentation data (if any)
2364 FDEAugmentation fdeAugmentation;
2365 error = cieAugmentation.ReadFDEData(dataReader,
2366 fdeAugmentation);
2367 if (error != B_OK) {
2368 TRACE_CFI(" failed to read FDE augmentation data!\n");
2369 return error;
2370 }
2371
2372 error = context.SaveInitialRuleSet();
2373 if (error != B_OK)
2374 return error;
2375
2376 uint64 remaining = lengthOffset + length - dataReader.Offset();
2377 if (remaining < 0)
2378 return B_BAD_DATA;
2379
2380 DataReader restrictedReader =
2381 dataReader.RestrictedReader(remaining);
2382 error = _ParseFrameInfoInstructions(unit, context,
2383 restrictedReader, cieAugmentation);
2384 if (error != B_OK)
2385 return error;
2386
2387 TRACE_CFI(" found row!\n");
2388
2389 // apply the rules of the final row
2390 // get the frameAddress first
2391 target_addr_t frameAddress;
2392 CfaCfaRule* cfaCfaRule = context.GetCfaCfaRule();
2393 switch (cfaCfaRule->Type()) {
2394 case CFA_CFA_RULE_REGISTER_OFFSET:
2395 {
2396 BVariant value;
2397 if (!inputInterface->GetRegisterValue(
2398 cfaCfaRule->Register(), value)
2399 || !value.IsNumber()) {
2400 return B_UNSUPPORTED;
2401 }
2402 frameAddress = value.ToUInt64() + cfaCfaRule->Offset();
2403 break;
2404 }
2405 case CFA_CFA_RULE_EXPRESSION:
2406 {
2407 error = EvaluateExpression(unit, addressSize, isBigEndian,
2408 subprogramEntry,
2409 cfaCfaRule->Expression().block,
2410 cfaCfaRule->Expression().size,
2411 inputInterface, location, 0, 0, false,
2412 frameAddress);
2413 if (error != B_OK)
2414 return error;
2415 break;
2416 }
2417 case CFA_CFA_RULE_UNDEFINED:
2418 default:
2419 return B_BAD_VALUE;
2420 }
2421
2422 TRACE_CFI(" frame address: %#" B_PRIx64 "\n", frameAddress);
2423
2424 // apply the register rules
2425 for (uint32 i = 0; i < registerCount; i++) {
2426 TRACE_CFI(" reg %" B_PRIu32 "\n", i);
2427
2428 uint32 valueType = outputInterface->RegisterValueType(i);
2429 if (valueType == 0)
2430 continue;
2431
2432 CfaRule* rule = context.RegisterRule(i);
2433 if (rule == NULL)
2434 continue;
2435
2436 // apply the rule
2437 switch (rule->Type()) {
2438 case CFA_RULE_SAME_VALUE:
2439 {
2440 TRACE_CFI(" -> CFA_RULE_SAME_VALUE\n");
2441
2442 BVariant value;
2443 if (inputInterface->GetRegisterValue(i, value))
2444 outputInterface->SetRegisterValue(i, value);
2445 break;
2446 }
2447 case CFA_RULE_LOCATION_OFFSET:
2448 {
2449 TRACE_CFI(" -> CFA_RULE_LOCATION_OFFSET: %"
2450 B_PRId64 "\n", rule->Offset());
2451
2452 BVariant value;
2453 if (inputInterface->ReadValueFromMemory(
2454 frameAddress + rule->Offset(), valueType,
2455 value)) {
2456 outputInterface->SetRegisterValue(i, value);
2457 }
2458 break;
2459 }
2460 case CFA_RULE_VALUE_OFFSET:
2461 TRACE_CFI(" -> CFA_RULE_VALUE_OFFSET\n");
2462
2463 outputInterface->SetRegisterValue(i,
2464 frameAddress + rule->Offset());
2465 break;
2466 case CFA_RULE_REGISTER:
2467 {
2468 TRACE_CFI(" -> CFA_RULE_REGISTER\n");
2469
2470 BVariant value;
2471 if (inputInterface->GetRegisterValue(
2472 rule->Register(), value)) {
2473 outputInterface->SetRegisterValue(i, value);
2474 }
2475 break;
2476 }
2477 case CFA_RULE_LOCATION_EXPRESSION:
2478 {
2479 TRACE_CFI(" -> CFA_RULE_LOCATION_EXPRESSION\n");
2480
2481 target_addr_t address;
2482 error = EvaluateExpression(unit, addressSize, isBigEndian,
2483 subprogramEntry,
2484 rule->Expression().block,
2485 rule->Expression().size,
2486 inputInterface, location, frameAddress,
2487 frameAddress, true, address);
2488 BVariant value;
2489 if (error == B_OK
2490 && inputInterface->ReadValueFromMemory(address,
2491 valueType, value)) {
2492 outputInterface->SetRegisterValue(i, value);
2493 }
2494 break;
2495 }
2496 case CFA_RULE_VALUE_EXPRESSION:
2497 {
2498 TRACE_CFI(" -> CFA_RULE_VALUE_EXPRESSION\n");
2499
2500 target_addr_t value;
2501 error = EvaluateExpression(unit, addressSize, isBigEndian,
2502 subprogramEntry,
2503 rule->Expression().block,
2504 rule->Expression().size,
2505 inputInterface, location, frameAddress,
2506 frameAddress, true, value);
2507 if (error == B_OK)
2508 outputInterface->SetRegisterValue(i, value);
2509 break;
2510 }
2511 case CFA_RULE_UNDEFINED:
2512 TRACE_CFI(" -> CFA_RULE_UNDEFINED\n");
2513 default:
2514 break;
2515 }
2516 }
2517
2518 _framePointer = frameAddress;
2519
2520 return B_OK;
2521 }
2522
2523
2524 status_t
_ParseCIEHeader(ElfSection * debugFrameSection,bool usingEHFrameSection,CompilationUnit * unit,uint8 addressSize,bool isBigEndian,CfaContext & context,off_t cieOffset,CIEAugmentation & cieAugmentation,DataReader & dataReader,off_t & _cieRemaining)2525 DwarfFile::_ParseCIEHeader(ElfSection* debugFrameSection,
2526 bool usingEHFrameSection, CompilationUnit* unit, uint8 addressSize, bool isBigEndian,
2527 CfaContext& context, off_t cieOffset, CIEAugmentation& cieAugmentation,
2528 DataReader& dataReader, off_t& _cieRemaining)
2529 {
2530 if (cieOffset < 0 || (uint64)cieOffset >= debugFrameSection->Size())
2531 return B_BAD_DATA;
2532
2533 dataReader.SetTo((uint8*)debugFrameSection->Data() + cieOffset,
2534 debugFrameSection->Size() - cieOffset,
2535 unit != NULL ? unit->AddressSize() : addressSize,
2536 unit != NULL ? unit->IsBigEndian() : isBigEndian);
2537
2538 // length
2539 bool dwarf64;
2540 uint64 length = dataReader.ReadInitialLength(dwarf64);
2541 if (length > (uint64)dataReader.BytesRemaining())
2542 return B_BAD_DATA;
2543
2544 off_t lengthOffset = dataReader.Offset();
2545
2546 // CIE ID/CIE pointer
2547 uint64 cieID = dwarf64
2548 ? dataReader.Read<uint64>(0) : dataReader.Read<uint32>(0);
2549 if (usingEHFrameSection) {
2550 if (cieID != 0)
2551 return B_BAD_DATA;
2552 } else {
2553 if (dwarf64 ? cieID != 0xffffffffffffffffULL : cieID != 0xffffffff)
2554 return B_BAD_DATA;
2555 }
2556
2557 uint8 version = dataReader.Read<uint8>(0);
2558 if (version != 1) {
2559 TRACE_CFI(" cie: length: %" B_PRIu64 ", offset: %#" B_PRIx64 ", "
2560 "version: %u -- unsupported\n", length, (uint64)cieOffset, version);
2561 return B_UNSUPPORTED;
2562 }
2563
2564 // read the augmentation string
2565 cieAugmentation.Init(dataReader);
2566
2567 // in the cause of augmentation string "eh",
2568 // the exception table pointer is located immediately before the
2569 // code/data alignment values. We have no use for it so simply skip.
2570 if (strcmp(cieAugmentation.String(), "eh") == 0)
2571 dataReader.Skip(dwarf64 ? sizeof(uint64) : sizeof(uint32));
2572
2573 context.SetCodeAlignment(dataReader.ReadUnsignedLEB128(0));
2574 context.SetDataAlignment(dataReader.ReadSignedLEB128(0));
2575 context.SetReturnAddressRegister(dataReader.ReadUnsignedLEB128(0));
2576
2577 TRACE_CFI(" cie: length: %" B_PRIu64 ", offset: %#" B_PRIx64 ", version: "
2578 "%u, augmentation: \"%s\", aligment: code: %" B_PRIu32 ", data: %"
2579 B_PRId32 ", return address reg: %" B_PRIu32 "\n", length,
2580 (uint64)cieOffset, version, cieAugmentation.String(),
2581 context.CodeAlignment(), context.DataAlignment(),
2582 context.ReturnAddressRegister());
2583
2584 status_t error = cieAugmentation.Read(dataReader);
2585 if (error != B_OK) {
2586 TRACE_CFI(" cie: length: %" B_PRIu64 ", version: %u, augmentation: "
2587 "\"%s\" -- unsupported\n", length, version,
2588 cieAugmentation.String());
2589 return error;
2590 }
2591
2592 if (dataReader.HasOverflow())
2593 return B_BAD_DATA;
2594
2595 _cieRemaining = length -(dataReader.Offset() - lengthOffset);
2596 if (_cieRemaining < 0)
2597 return B_BAD_DATA;
2598
2599 return B_OK;
2600 }
2601
2602
2603 status_t
_ParseFrameInfoInstructions(CompilationUnit * unit,CfaContext & context,DataReader & dataReader,CIEAugmentation & augmentation)2604 DwarfFile::_ParseFrameInfoInstructions(CompilationUnit* unit,
2605 CfaContext& context, DataReader& dataReader, CIEAugmentation& augmentation)
2606 {
2607 while (dataReader.BytesRemaining() > 0) {
2608 TRACE_CFI(" [%2" B_PRId64 "]", dataReader.BytesRemaining());
2609
2610 uint8 opcode = dataReader.Read<uint8>(0);
2611 if ((opcode >> 6) != 0) {
2612 uint32 operand = opcode & 0x3f;
2613
2614 switch (opcode >> 6) {
2615 case DW_CFA_advance_loc:
2616 {
2617 TRACE_CFI(" DW_CFA_advance_loc: %#" B_PRIx32 "\n",
2618 operand);
2619
2620 target_addr_t location = context.Location()
2621 + operand * context.CodeAlignment();
2622 if (location > context.TargetLocation())
2623 return B_OK;
2624 context.SetLocation(location);
2625 break;
2626 }
2627 case DW_CFA_offset:
2628 {
2629 uint64 offset = dataReader.ReadUnsignedLEB128(0);
2630 TRACE_CFI(" DW_CFA_offset: reg: %" B_PRIu32 ", offset: "
2631 "%" B_PRIu64 "\n", operand, offset);
2632
2633 if (CfaRule* rule = context.RegisterRule(operand)) {
2634 rule->SetToLocationOffset(
2635 offset * context.DataAlignment());
2636 }
2637 break;
2638 }
2639 case DW_CFA_restore:
2640 {
2641 TRACE_CFI(" DW_CFA_restore: %#" B_PRIx32 "\n", operand);
2642
2643 context.RestoreRegisterRule(operand);
2644 break;
2645 }
2646 }
2647 } else {
2648 switch (opcode) {
2649 case DW_CFA_nop:
2650 {
2651 TRACE_CFI(" DW_CFA_nop\n");
2652 break;
2653 }
2654 case DW_CFA_set_loc:
2655 {
2656 target_addr_t location = augmentation.ReadEncodedAddress(
2657 dataReader, fElfFile, fDebugFrameSection);
2658
2659 TRACE_CFI(" DW_CFA_set_loc: %#" B_PRIx64 "\n", location);
2660
2661 if (location < context.Location())
2662 return B_BAD_VALUE;
2663 if (location > context.TargetLocation())
2664 return B_OK;
2665 context.SetLocation(location);
2666 break;
2667 }
2668 case DW_CFA_advance_loc1:
2669 {
2670 uint32 delta = dataReader.Read<uint8>(0);
2671
2672 TRACE_CFI(" DW_CFA_advance_loc1: %#" B_PRIx32 "\n",
2673 delta);
2674
2675 target_addr_t location = context.Location()
2676 + delta * context.CodeAlignment();
2677 if (location > context.TargetLocation())
2678 return B_OK;
2679 context.SetLocation(location);
2680 break;
2681 }
2682 case DW_CFA_advance_loc2:
2683 {
2684 uint32 delta = dataReader.Read<uint16>(0);
2685
2686 TRACE_CFI(" DW_CFA_advance_loc2: %#" B_PRIx32 "\n",
2687 delta);
2688
2689 target_addr_t location = context.Location()
2690 + delta * context.CodeAlignment();
2691 if (location > context.TargetLocation())
2692 return B_OK;
2693 context.SetLocation(location);
2694 break;
2695 }
2696 case DW_CFA_advance_loc4:
2697 {
2698 uint32 delta = dataReader.Read<uint32>(0);
2699
2700 TRACE_CFI(" DW_CFA_advance_loc4: %#" B_PRIx32 "\n",
2701 delta);
2702
2703 target_addr_t location = context.Location()
2704 + delta * context.CodeAlignment();
2705 if (location > context.TargetLocation())
2706 return B_OK;
2707 context.SetLocation(location);
2708 break;
2709 }
2710 case DW_CFA_offset_extended:
2711 {
2712 uint32 reg = dataReader.ReadUnsignedLEB128(0);
2713 uint64 offset = dataReader.ReadUnsignedLEB128(0);
2714
2715 TRACE_CFI(" DW_CFA_offset_extended: reg: %" B_PRIu32 ", "
2716 "offset: %" B_PRIu64 "\n", reg, offset);
2717
2718 if (CfaRule* rule = context.RegisterRule(reg)) {
2719 rule->SetToLocationOffset(
2720 offset * context.DataAlignment());
2721 }
2722 break;
2723 }
2724 case DW_CFA_restore_extended:
2725 {
2726 uint32 reg = dataReader.ReadUnsignedLEB128(0);
2727
2728 TRACE_CFI(" DW_CFA_restore_extended: %#" B_PRIx32 "\n",
2729 reg);
2730
2731 context.RestoreRegisterRule(reg);
2732 break;
2733 }
2734 case DW_CFA_undefined:
2735 {
2736 uint32 reg = dataReader.ReadUnsignedLEB128(0);
2737
2738 TRACE_CFI(" DW_CFA_undefined: %" B_PRIu32 "\n", reg);
2739
2740 if (CfaRule* rule = context.RegisterRule(reg))
2741 rule->SetToUndefined();
2742 break;
2743 }
2744 case DW_CFA_same_value:
2745 {
2746 uint32 reg = dataReader.ReadUnsignedLEB128(0);
2747
2748 TRACE_CFI(" DW_CFA_same_value: %" B_PRIu32 "\n", reg);
2749
2750 if (CfaRule* rule = context.RegisterRule(reg))
2751 rule->SetToSameValue();
2752 break;
2753 }
2754 case DW_CFA_register:
2755 {
2756 uint32 reg1 = dataReader.ReadUnsignedLEB128(0);
2757 uint32 reg2 = dataReader.ReadUnsignedLEB128(0);
2758
2759 TRACE_CFI(" DW_CFA_register: reg1: %" B_PRIu32 ", reg2: "
2760 "%" B_PRIu32 "\n", reg1, reg2);
2761
2762 if (CfaRule* rule = context.RegisterRule(reg1))
2763 rule->SetToValueOffset(reg2);
2764 break;
2765 }
2766 case DW_CFA_remember_state:
2767 {
2768 TRACE_CFI(" DW_CFA_remember_state\n");
2769
2770 status_t error = context.PushRuleSet();
2771 if (error != B_OK)
2772 return error;
2773 break;
2774 }
2775 case DW_CFA_restore_state:
2776 {
2777 TRACE_CFI(" DW_CFA_restore_state\n");
2778
2779 status_t error = context.PopRuleSet();
2780 if (error != B_OK)
2781 return error;
2782 break;
2783 }
2784 case DW_CFA_def_cfa:
2785 {
2786 uint32 reg = dataReader.ReadUnsignedLEB128(0);
2787 uint64 offset = dataReader.ReadUnsignedLEB128(0);
2788
2789 TRACE_CFI(" DW_CFA_def_cfa: reg: %" B_PRIu32 ", offset: "
2790 "%" B_PRIu64 "\n", reg, offset);
2791
2792 context.GetCfaCfaRule()->SetToRegisterOffset(reg, offset);
2793 break;
2794 }
2795 case DW_CFA_def_cfa_register:
2796 {
2797 uint32 reg = dataReader.ReadUnsignedLEB128(0);
2798
2799 TRACE_CFI(" DW_CFA_def_cfa_register: %" B_PRIu32 "\n",
2800 reg);
2801
2802 if (context.GetCfaCfaRule()->Type()
2803 != CFA_CFA_RULE_REGISTER_OFFSET) {
2804 return B_BAD_DATA;
2805 }
2806 context.GetCfaCfaRule()->SetRegister(reg);
2807 break;
2808 }
2809 case DW_CFA_def_cfa_offset:
2810 {
2811 uint64 offset = dataReader.ReadUnsignedLEB128(0);
2812
2813 TRACE_CFI(" DW_CFA_def_cfa_offset: %" B_PRIu64 "\n",
2814 offset);
2815
2816 if (context.GetCfaCfaRule()->Type()
2817 != CFA_CFA_RULE_REGISTER_OFFSET) {
2818 return B_BAD_DATA;
2819 }
2820 context.GetCfaCfaRule()->SetOffset(offset);
2821 break;
2822 }
2823 case DW_CFA_def_cfa_expression:
2824 {
2825 uint64 blockLength = dataReader.ReadUnsignedLEB128(0);
2826 uint8* block = (uint8*)dataReader.Data();
2827 dataReader.Skip(blockLength);
2828
2829 TRACE_CFI(" DW_CFA_def_cfa_expression: %p, %" B_PRIu64
2830 "\n", block, blockLength);
2831
2832 context.GetCfaCfaRule()->SetToExpression(block,
2833 blockLength);
2834 break;
2835 }
2836 case DW_CFA_expression:
2837 {
2838 uint32 reg = dataReader.ReadUnsignedLEB128(0);
2839 uint64 blockLength = dataReader.ReadUnsignedLEB128(0);
2840 uint8* block = (uint8*)dataReader.Data();
2841 dataReader.Skip(blockLength);
2842
2843 TRACE_CFI(" DW_CFA_expression: reg: %" B_PRIu32 ", "
2844 "block: %p, %" B_PRIu64 "\n", reg, block, blockLength);
2845
2846 if (CfaRule* rule = context.RegisterRule(reg))
2847 rule->SetToLocationExpression(block, blockLength);
2848 break;
2849 }
2850 case DW_CFA_offset_extended_sf:
2851 {
2852 uint32 reg = dataReader.ReadUnsignedLEB128(0);
2853 int64 offset = dataReader.ReadSignedLEB128(0);
2854
2855 TRACE_CFI(" DW_CFA_offset_extended: reg: %" B_PRIu32 ", "
2856 "offset: %" B_PRId64 "\n", reg, offset);
2857
2858 if (CfaRule* rule = context.RegisterRule(reg)) {
2859 rule->SetToLocationOffset(
2860 offset * (int32)context.DataAlignment());
2861 }
2862 break;
2863 }
2864 case DW_CFA_def_cfa_sf:
2865 {
2866 uint32 reg = dataReader.ReadUnsignedLEB128(0);
2867 int64 offset = dataReader.ReadSignedLEB128(0);
2868
2869 TRACE_CFI(" DW_CFA_def_cfa_sf: reg: %" B_PRIu32 ", "
2870 "offset: %" B_PRId64 "\n", reg, offset);
2871
2872 context.GetCfaCfaRule()->SetToRegisterOffset(reg,
2873 offset * (int32)context.DataAlignment());
2874 break;
2875 }
2876 case DW_CFA_def_cfa_offset_sf:
2877 {
2878 int64 offset = dataReader.ReadSignedLEB128(0);
2879
2880 TRACE_CFI(" DW_CFA_def_cfa_offset: %" B_PRId64 "\n",
2881 offset);
2882
2883 if (context.GetCfaCfaRule()->Type()
2884 != CFA_CFA_RULE_REGISTER_OFFSET) {
2885 return B_BAD_DATA;
2886 }
2887 context.GetCfaCfaRule()->SetOffset(
2888 offset * (int32)context.DataAlignment());
2889 break;
2890 }
2891 case DW_CFA_val_offset:
2892 {
2893 uint32 reg = dataReader.ReadUnsignedLEB128(0);
2894 uint64 offset = dataReader.ReadUnsignedLEB128(0);
2895
2896 TRACE_CFI(" DW_CFA_val_offset: reg: %" B_PRIu32 ", "
2897 "offset: %" B_PRIu64 "\n", reg, offset);
2898
2899 if (CfaRule* rule = context.RegisterRule(reg)) {
2900 rule->SetToValueOffset(
2901 offset * context.DataAlignment());
2902 }
2903 break;
2904 }
2905 case DW_CFA_val_offset_sf:
2906 {
2907 uint32 reg = dataReader.ReadUnsignedLEB128(0);
2908 int64 offset = dataReader.ReadSignedLEB128(0);
2909
2910 TRACE_CFI(" DW_CFA_val_offset_sf: reg: %" B_PRIu32 ", "
2911 "offset: %" B_PRId64 "\n", reg, offset);
2912
2913 if (CfaRule* rule = context.RegisterRule(reg)) {
2914 rule->SetToValueOffset(
2915 offset * (int32)context.DataAlignment());
2916 }
2917 break;
2918 }
2919 case DW_CFA_val_expression:
2920 {
2921 uint32 reg = dataReader.ReadUnsignedLEB128(0);
2922 uint64 blockLength = dataReader.ReadUnsignedLEB128(0);
2923 uint8* block = (uint8*)dataReader.Data();
2924 dataReader.Skip(blockLength);
2925
2926 TRACE_CFI(" DW_CFA_val_expression: reg: %" B_PRIu32 ", "
2927 "block: %p, %" B_PRIu64 "\n", reg, block, blockLength);
2928
2929 if (CfaRule* rule = context.RegisterRule(reg))
2930 rule->SetToValueExpression(block, blockLength);
2931 break;
2932 }
2933
2934 // extensions
2935 case DW_CFA_MIPS_advance_loc8:
2936 {
2937 uint64 delta = dataReader.Read<uint64>(0);
2938
2939 TRACE_CFI(" DW_CFA_MIPS_advance_loc8: %#" B_PRIx64 "\n",
2940 delta);
2941
2942 target_addr_t location = context.Location()
2943 + delta * context.CodeAlignment();
2944 if (location > context.TargetLocation())
2945 return B_OK;
2946 context.SetLocation(location);
2947 break;
2948 }
2949 case DW_CFA_GNU_window_save:
2950 {
2951 // SPARC specific, no args
2952 TRACE_CFI(" DW_CFA_GNU_window_save\n");
2953
2954 // TODO: Implement once we have SPARC support!
2955 break;
2956 }
2957 case DW_CFA_GNU_args_size:
2958 {
2959 // Updates the total size of arguments on the stack.
2960 TRACE_CFI_ONLY(uint64 size =)
2961 dataReader.ReadUnsignedLEB128(0);
2962
2963 TRACE_CFI(" DW_CFA_GNU_args_size: %" B_PRIu64 "\n",
2964 size);
2965 // TODO: Implement!
2966 break;
2967 }
2968 case DW_CFA_GNU_negative_offset_extended:
2969 {
2970 // obsolete
2971 uint32 reg = dataReader.ReadUnsignedLEB128(0);
2972 int64 offset = dataReader.ReadSignedLEB128(0);
2973
2974 TRACE_CFI(" DW_CFA_GNU_negative_offset_extended: "
2975 "reg: %" B_PRIu32 ", offset: %" B_PRId64 "\n", reg,
2976 offset);
2977
2978 if (CfaRule* rule = context.RegisterRule(reg)) {
2979 rule->SetToLocationOffset(
2980 offset * (int32)context.DataAlignment());
2981 }
2982 break;
2983 }
2984
2985 default:
2986 TRACE_CFI(" unknown opcode %u!\n", opcode);
2987 return B_BAD_DATA;
2988 }
2989 }
2990 }
2991
2992 return B_OK;
2993 }
2994
2995
2996 status_t
_ParsePublicTypesInfo(uint8 _addressSize,bool isBigEndian)2997 DwarfFile::_ParsePublicTypesInfo(uint8 _addressSize, bool isBigEndian)
2998 {
2999 TRACE_PUBTYPES("DwarfFile::_ParsePublicTypesInfo()\n");
3000 if (fDebugPublicTypesSection == NULL) {
3001 TRACE_PUBTYPES(" -> no public types section\n");
3002 return B_ENTRY_NOT_FOUND;
3003 }
3004
3005 DataReader dataReader((uint8*)fDebugPublicTypesSection->Data(),
3006 fDebugPublicTypesSection->Size(), _addressSize, isBigEndian);
3007
3008 while (dataReader.BytesRemaining() > 0) {
3009 bool dwarf64;
3010 uint64 unitLength = dataReader.ReadInitialLength(dwarf64);
3011
3012 off_t unitLengthOffset = dataReader.Offset();
3013 // the unitLength starts here
3014
3015 if (dataReader.HasOverflow())
3016 return B_BAD_DATA;
3017
3018 if (unitLengthOffset + unitLength
3019 > (uint64)fDebugPublicTypesSection->Size()) {
3020 WARNING("Invalid public types set unit length.\n");
3021 break;
3022 }
3023
3024 DataReader unitDataReader(dataReader.Data(), unitLength, _addressSize, isBigEndian);
3025 _ParsePublicTypesInfo(unitDataReader, dwarf64);
3026
3027 dataReader.SeekAbsolute(unitLengthOffset + unitLength);
3028 }
3029
3030 return B_OK;
3031 }
3032
3033
3034 status_t
_ParsePublicTypesInfo(DataReader & dataReader,bool dwarf64)3035 DwarfFile::_ParsePublicTypesInfo(DataReader& dataReader, bool dwarf64)
3036 {
3037 int version = dataReader.Read<uint16>(0);
3038 if (version != 2) {
3039 TRACE_PUBTYPES(" pubtypes version %d unsupported\n", version);
3040 return B_UNSUPPORTED;
3041 }
3042
3043 TRACE_PUBTYPES_ONLY(off_t debugInfoOffset =) dwarf64
3044 ? dataReader.Read<uint64>(0)
3045 : (uint64)dataReader.Read<uint32>(0);
3046 TRACE_PUBTYPES_ONLY(off_t debugInfoSize =) dwarf64
3047 ? dataReader.Read<uint64>(0)
3048 : (uint64)dataReader.Read<uint32>(0);
3049
3050 if (dataReader.HasOverflow())
3051 return B_BAD_DATA;
3052
3053 TRACE_PUBTYPES("DwarfFile::_ParsePublicTypesInfo(): compilation unit debug "
3054 "info: (%" B_PRIdOFF ", %" B_PRIdOFF ")\n", debugInfoOffset,
3055 debugInfoSize);
3056
3057 while (dataReader.BytesRemaining() > 0) {
3058 off_t entryOffset = dwarf64
3059 ? dataReader.Read<uint64>(0)
3060 : (uint64)dataReader.Read<uint32>(0);
3061 if (entryOffset == 0)
3062 return B_OK;
3063
3064 TRACE_PUBTYPES_ONLY(const char* name =) dataReader.ReadString();
3065
3066 TRACE_PUBTYPES(" \"%s\" -> %" B_PRIdOFF "\n", name, entryOffset);
3067 }
3068
3069 return B_OK;
3070 }
3071
3072
3073 status_t
_GetAbbreviationTable(off_t offset,AbbreviationTable * & _table)3074 DwarfFile::_GetAbbreviationTable(off_t offset, AbbreviationTable*& _table)
3075 {
3076 // check, whether we've already loaded it
3077 for (AbbreviationTableList::Iterator it
3078 = fAbbreviationTables.GetIterator();
3079 AbbreviationTable* table = it.Next();) {
3080 if (offset == table->Offset()) {
3081 _table = table;
3082 return B_OK;
3083 }
3084 }
3085
3086 // create a new table
3087 AbbreviationTable* table = new(std::nothrow) AbbreviationTable(offset);
3088 if (table == NULL)
3089 return B_NO_MEMORY;
3090
3091 status_t error = table->Init(fDebugAbbrevSection->Data(),
3092 fDebugAbbrevSection->Size());
3093 if (error != B_OK) {
3094 delete table;
3095 return error;
3096 }
3097
3098 fAbbreviationTables.Add(table);
3099 _table = table;
3100 return B_OK;
3101 }
3102
3103
3104 DebugInfoEntry*
_ResolveReference(BaseUnit * unit,uint64 offset,uint8 refType) const3105 DwarfFile::_ResolveReference(BaseUnit* unit, uint64 offset,
3106 uint8 refType) const
3107 {
3108 switch (refType) {
3109 case dwarf_reference_type_local:
3110 return unit->EntryForOffset(offset);
3111 break;
3112 case dwarf_reference_type_global:
3113 {
3114 CompilationUnit* unit = _GetContainingCompilationUnit(offset);
3115 if (unit == NULL)
3116 break;
3117
3118 offset -= unit->HeaderOffset();
3119 DebugInfoEntry* entry = unit->EntryForOffset(offset);
3120 if (entry != NULL)
3121 return entry;
3122 break;
3123 }
3124 case dwarf_reference_type_signature:
3125 {
3126 TRACE_DIE("Resolving signature %#" B_PRIx64 "\n", offset);
3127 TypeUnitTableEntry* entry = fTypeUnits.Lookup(offset);
3128 if (entry != NULL && entry->unit != NULL)
3129 return entry->unit->TypeEntry();
3130 break;
3131 }
3132 }
3133
3134 return NULL;
3135 }
3136
3137
3138 status_t
_GetLocationExpression(CompilationUnit * unit,const LocationDescription * location,target_addr_t instructionPointer,const void * & _expression,off_t & _length) const3139 DwarfFile::_GetLocationExpression(CompilationUnit* unit,
3140 const LocationDescription* location, target_addr_t instructionPointer,
3141 const void*& _expression, off_t& _length) const
3142 {
3143 if (!location->IsValid())
3144 return B_BAD_VALUE;
3145
3146 if (location->IsExpression()) {
3147 _expression = location->expression.data;
3148 _length = location->expression.length;
3149 return B_OK;
3150 }
3151
3152 if (location->IsLocationList() && instructionPointer != 0) {
3153 return _FindLocationExpression(unit, location->listOffset,
3154 instructionPointer, _expression, _length);
3155 }
3156
3157 return B_BAD_VALUE;
3158 }
3159
3160
3161 status_t
_FindLocationExpression(CompilationUnit * unit,uint64 offset,target_addr_t address,const void * & _expression,off_t & _length) const3162 DwarfFile::_FindLocationExpression(CompilationUnit* unit, uint64 offset,
3163 target_addr_t address, const void*& _expression, off_t& _length) const
3164 {
3165 if (unit == NULL)
3166 return B_BAD_VALUE;
3167
3168 if (fDebugLocationSection == NULL)
3169 return B_ENTRY_NOT_FOUND;
3170
3171 if (offset < 0 || offset >= (uint64)fDebugLocationSection->Size())
3172 return B_BAD_DATA;
3173
3174 target_addr_t baseAddress = unit->AddressRangeBase();
3175 target_addr_t maxAddress = unit->MaxAddress();
3176
3177 DataReader dataReader((uint8*)fDebugLocationSection->Data() + offset,
3178 fDebugLocationSection->Size() - offset, unit->AddressSize(), unit->IsBigEndian());
3179 while (true) {
3180 target_addr_t start = dataReader.ReadAddress(0);
3181 target_addr_t end = dataReader.ReadAddress(0);
3182 if (dataReader.HasOverflow())
3183 return B_BAD_DATA;
3184
3185 if (start == 0 && end == 0)
3186 return B_ENTRY_NOT_FOUND;
3187
3188 if (start == maxAddress) {
3189 baseAddress = end;
3190 continue;
3191 }
3192
3193 uint16 expressionLength = dataReader.Read<uint16>(0);
3194 const void* expression = dataReader.Data();
3195 if (!dataReader.Skip(expressionLength))
3196 return B_BAD_DATA;
3197
3198 if (start == end)
3199 continue;
3200
3201 start += baseAddress;
3202 end += baseAddress;
3203
3204 if (address >= start && address < end) {
3205 _expression = expression;
3206 _length = expressionLength;
3207 return B_OK;
3208 }
3209 }
3210 }
3211
3212
3213 status_t
_LocateDebugInfo(BString & _requiredExternalFileName,const char * locatedFilePath)3214 DwarfFile::_LocateDebugInfo(BString& _requiredExternalFileName,
3215 const char* locatedFilePath)
3216 {
3217 ElfFile* debugInfoFile = fElfFile;
3218 ElfSection* debugLinkSection = fElfFile->GetSection(".gnu_debuglink");
3219 if (debugLinkSection != NULL) {
3220 AutoSectionPutter putter(fElfFile, debugLinkSection);
3221
3222 // the file specifies a debug link, look at its target instead
3223 // for debug information.
3224 // Format: null-terminated filename, as many 0 padding bytes as
3225 // needed to reach the next 32-bit address boundary, followed
3226 // by a 32-bit CRC
3227
3228 BString debugPath;
3229 if (locatedFilePath)
3230 debugPath = locatedFilePath;
3231 else {
3232 status_t result = _GetDebugInfoPath(
3233 (const char*)debugLinkSection->Data(),
3234 _requiredExternalFileName);
3235 if (result != B_OK)
3236 return result;
3237 debugPath = _requiredExternalFileName;
3238 }
3239
3240 if (fAlternateName != NULL)
3241 free(fAlternateName);
3242
3243 fAlternateName = strdup(debugPath.String());
3244
3245 if (fAlternateName == NULL)
3246 return B_NO_MEMORY;
3247
3248 /*
3249 // TODO: validate CRC
3250 int32 debugCRC = *(int32*)((char*)debugLinkSection->Data()
3251 + debugLinkSection->Size() - sizeof(int32));
3252 */
3253 if (fAlternateElfFile == NULL) {
3254 fAlternateElfFile = new(std::nothrow) ElfFile;
3255 if (fAlternateElfFile == NULL)
3256 return B_NO_MEMORY;
3257 }
3258
3259 status_t result = fAlternateElfFile->Init(fAlternateName);
3260 if (result != B_OK)
3261 return result;
3262
3263 debugInfoFile = fAlternateElfFile;
3264 }
3265
3266 // get the interesting sections
3267 fDebugInfoSection = debugInfoFile->GetSection(".debug_info");
3268 fDebugAbbrevSection = debugInfoFile->GetSection(".debug_abbrev");
3269 if (fDebugInfoSection == NULL || fDebugAbbrevSection == NULL) {
3270 TRACE_DIE("DwarfManager::File::Load(\"%s\"): no "
3271 ".debug_info or .debug_abbrev.\n", fName);
3272
3273 // if we at least have an EH frame, use that for stack unwinding
3274 // if nothing else.
3275 fEHFrameSection = fElfFile->GetSection(".eh_frame");
3276 if (fEHFrameSection == NULL)
3277 return B_ERROR;
3278 }
3279
3280 return B_OK;
3281 }
3282
3283
3284 status_t
_GetDebugInfoPath(const char * debugFileName,BString & _infoPath) const3285 DwarfFile::_GetDebugInfoPath(const char* debugFileName,
3286 BString& _infoPath) const
3287 {
3288 // first, see if we have a relative match to our local directory
3289 BPath basePath;
3290 status_t result = basePath.SetTo(fName);
3291 if (result != B_OK)
3292 return result;
3293 basePath.GetParent(&basePath);
3294 if (strcmp(basePath.Leaf(), "lib") == 0 || strcmp(basePath.Leaf(),
3295 "add-ons") == 0) {
3296 _infoPath.SetToFormat("%s/../debug/%s", basePath.Path(),
3297 debugFileName);
3298 } else
3299 _infoPath.SetToFormat("%s/debug/%s", basePath.Path(), debugFileName);
3300
3301 BEntry entry(_infoPath.String());
3302 result = entry.InitCheck();
3303 if (result != B_OK && result != B_ENTRY_NOT_FOUND)
3304 return result;
3305 if (entry.Exists())
3306 return B_OK;
3307
3308 // If the above search failed, check if our image is located in any
3309 // of the system installation paths, and attempt to locate the debug info
3310 // file in the corresponding well-known location
3311 BString pathSuffix;
3312 pathSuffix.SetToFormat("debug/%s", debugFileName);
3313
3314 BPathFinder finder(fName);
3315 result = finder.FindPath(B_FIND_PATH_DEVELOP_DIRECTORY,
3316 pathSuffix.String(), B_FIND_PATH_EXISTING_ONLY, basePath);
3317 if (result == B_OK) {
3318 _infoPath = basePath.Path();
3319 return B_OK;
3320 } else {
3321 // if we failed to find a match, then it's up to the user to
3322 // locate it. As such, return the external info file name
3323 // for user interface purposes.
3324 _infoPath.SetTo(debugFileName);
3325 }
3326
3327 return B_ENTRY_NOT_FOUND;
3328 }
3329
3330
3331 TypeUnitTableEntry*
_GetTypeUnit(uint64 signature) const3332 DwarfFile::_GetTypeUnit(uint64 signature) const
3333 {
3334 return fTypeUnits.Lookup(signature);
3335 }
3336
3337
3338 CompilationUnit*
_GetContainingCompilationUnit(off_t refAddr) const3339 DwarfFile::_GetContainingCompilationUnit(off_t refAddr) const
3340 {
3341 if (fCompilationUnits.IsEmpty())
3342 return NULL;
3343
3344 // binary search
3345 int lower = 0;
3346 int upper = fCompilationUnits.CountItems() - 1;
3347 while (lower < upper) {
3348 int mid = (lower + upper + 1) / 2;
3349 if (fCompilationUnits.ItemAt(mid)->HeaderOffset() > refAddr)
3350 upper = mid - 1;
3351 else
3352 lower = mid;
3353 }
3354
3355 CompilationUnit* unit = fCompilationUnits.ItemAt(lower);
3356 return unit->ContainsAbsoluteOffset(refAddr) ? unit : NULL;
3357 }
3358
3359
3360 DwarfFile::FDELookupInfo*
_GetContainingFDEInfo(target_addr_t offset) const3361 DwarfFile::_GetContainingFDEInfo(target_addr_t offset) const
3362 {
3363 FDELookupInfo* info = NULL;
3364 if (fDebugFrameSection != NULL) {
3365 info = _GetContainingFDEInfo(offset, fDebugFrameInfos);
3366 if (info != NULL)
3367 return info;
3368 }
3369
3370 return _GetContainingFDEInfo(offset, fEHFrameInfos);
3371 }
3372
3373
3374 DwarfFile::FDELookupInfo*
_GetContainingFDEInfo(target_addr_t offset,const FDEInfoList & infoList) const3375 DwarfFile::_GetContainingFDEInfo(target_addr_t offset,
3376 const FDEInfoList& infoList) const
3377 {
3378 // binary search
3379 int lower = 0;
3380 int upper = infoList.CountItems() - 1;
3381 if (upper < 0)
3382 return NULL;
3383
3384 while (lower < upper) {
3385 int mid = (lower + upper + 1) / 2;
3386 if (offset < infoList.ItemAt(mid)->start)
3387 upper = mid - 1;
3388 else
3389 lower = mid;
3390 }
3391
3392 FDELookupInfo* info = infoList.ItemAt(lower);
3393 return info->ContainsAddress(offset) ? info : NULL;
3394 }
3395