| //===- DWARFDebugPubTable.cpp ---------------------------------------------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "llvm/DebugInfo/DWARF/DWARFDebugPubTable.h" |
| #include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h" |
| #include "llvm/ADT/StringRef.h" |
| #include "llvm/BinaryFormat/Dwarf.h" |
| #include "llvm/Support/DataExtractor.h" |
| #include "llvm/Support/Errc.h" |
| #include "llvm/Support/Format.h" |
| #include "llvm/Support/raw_ostream.h" |
| #include <cstdint> |
| |
| using namespace llvm; |
| using namespace dwarf; |
| |
| void DWARFDebugPubTable::extract( |
| DWARFDataExtractor Data, bool GnuStyle, |
| function_ref<void(Error)> RecoverableErrorHandler) { |
| this->GnuStyle = GnuStyle; |
| Sets.clear(); |
| uint64_t Offset = 0; |
| while (Data.isValidOffset(Offset)) { |
| uint64_t SetOffset = Offset; |
| Sets.push_back({}); |
| Set &NewSet = Sets.back(); |
| |
| DataExtractor::Cursor C(Offset); |
| std::tie(NewSet.Length, NewSet.Format) = Data.getInitialLength(C); |
| if (!C) { |
| // Drop the newly added set because it does not contain anything useful |
| // to dump. |
| Sets.pop_back(); |
| RecoverableErrorHandler(createStringError( |
| errc::invalid_argument, |
| "name lookup table at offset 0x%" PRIx64 " parsing failed: %s", |
| SetOffset, toString(C.takeError()).c_str())); |
| return; |
| } |
| |
| Offset = C.tell() + NewSet.Length; |
| DWARFDataExtractor SetData(Data, Offset); |
| const unsigned OffsetSize = dwarf::getDwarfOffsetByteSize(NewSet.Format); |
| |
| NewSet.Version = SetData.getU16(C); |
| NewSet.Offset = SetData.getRelocatedValue(C, OffsetSize); |
| NewSet.Size = SetData.getUnsigned(C, OffsetSize); |
| |
| if (!C) { |
| // Preserve the newly added set because at least some fields of the header |
| // are read and can be dumped. |
| RecoverableErrorHandler( |
| createStringError(errc::invalid_argument, |
| "name lookup table at offset 0x%" PRIx64 |
| " does not have a complete header: %s", |
| SetOffset, toString(C.takeError()).c_str())); |
| continue; |
| } |
| |
| while (C) { |
| uint64_t DieRef = SetData.getUnsigned(C, OffsetSize); |
| if (DieRef == 0) |
| break; |
| uint8_t IndexEntryValue = GnuStyle ? SetData.getU8(C) : 0; |
| StringRef Name = SetData.getCStrRef(C); |
| if (C) |
| NewSet.Entries.push_back( |
| {DieRef, PubIndexEntryDescriptor(IndexEntryValue), Name}); |
| } |
| |
| if (!C) { |
| RecoverableErrorHandler(createStringError( |
| errc::invalid_argument, |
| "name lookup table at offset 0x%" PRIx64 " parsing failed: %s", |
| SetOffset, toString(C.takeError()).c_str())); |
| continue; |
| } |
| if (C.tell() != Offset) |
| RecoverableErrorHandler(createStringError( |
| errc::invalid_argument, |
| "name lookup table at offset 0x%" PRIx64 |
| " has a terminator at offset 0x%" PRIx64 |
| " before the expected end at 0x%" PRIx64, |
| SetOffset, C.tell() - OffsetSize, Offset - OffsetSize)); |
| } |
| } |
| |
| void DWARFDebugPubTable::dump(raw_ostream &OS) const { |
| for (const Set &S : Sets) { |
| int OffsetDumpWidth = 2 * dwarf::getDwarfOffsetByteSize(S.Format); |
| OS << "length = " << format("0x%0*" PRIx64, OffsetDumpWidth, S.Length); |
| OS << ", format = " << dwarf::FormatString(S.Format); |
| OS << ", version = " << format("0x%04x", S.Version); |
| OS << ", unit_offset = " |
| << format("0x%0*" PRIx64, OffsetDumpWidth, S.Offset); |
| OS << ", unit_size = " << format("0x%0*" PRIx64, OffsetDumpWidth, S.Size) |
| << '\n'; |
| OS << (GnuStyle ? "Offset Linkage Kind Name\n" |
| : "Offset Name\n"); |
| |
| for (const Entry &E : S.Entries) { |
| OS << format("0x%0*" PRIx64 " ", OffsetDumpWidth, E.SecOffset); |
| if (GnuStyle) { |
| StringRef EntryLinkage = |
| GDBIndexEntryLinkageString(E.Descriptor.Linkage); |
| StringRef EntryKind = dwarf::GDBIndexEntryKindString(E.Descriptor.Kind); |
| OS << format("%-8s", EntryLinkage.data()) << ' ' |
| << format("%-8s", EntryKind.data()) << ' '; |
| } |
| OS << '\"' << E.Name << "\"\n"; |
| } |
| } |
| } |