diff --git a/tools/llvm-objdump/MachODump.cpp b/tools/llvm-objdump/MachODump.cpp index 9908c2f2d01..aa6122b05f8 100644 --- a/tools/llvm-objdump/MachODump.cpp +++ b/tools/llvm-objdump/MachODump.cpp @@ -7310,12 +7310,25 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF, namespace { -template static uint64_t readNext(const char *&Buf) { +template +static uint64_t read(StringRef Contents, ptrdiff_t Offset) { using llvm::support::little; using llvm::support::unaligned; - uint64_t Val = support::endian::read(Buf); - Buf += sizeof(T); + if (Offset + sizeof(T) > Contents.size()) { + outs() << "warning: attempt to read past end of buffer\n"; + return T(); + } + + uint64_t Val = + support::endian::read(Contents.data() + Offset); + return Val; +} + +template +static uint64_t readNext(StringRef Contents, ptrdiff_t &Offset) { + T Val = read(Contents, Offset); + Offset += sizeof(T); return Val; } @@ -7335,18 +7348,18 @@ struct CompactUnwindEntry { CompactUnwindEntry(StringRef Contents, unsigned Offset, bool Is64) : OffsetInSection(Offset) { if (Is64) - read(Contents.data() + Offset); + read(Contents, Offset); else - read(Contents.data() + Offset); + read(Contents, Offset); } private: - template void read(const char *Buf) { - FunctionAddr = readNext(Buf); - Length = readNext(Buf); - CompactEncoding = readNext(Buf); - PersonalityAddr = readNext(Buf); - LSDAAddr = readNext(Buf); + template void read(StringRef Contents, ptrdiff_t Offset) { + FunctionAddr = readNext(Contents, Offset); + Length = readNext(Contents, Offset); + CompactEncoding = readNext(Contents, Offset); + PersonalityAddr = readNext(Contents, Offset); + LSDAAddr = readNext(Contents, Offset); } }; } @@ -7448,7 +7461,7 @@ printMachOCompactUnwindSection(const MachOObjectFile *Obj, // First populate the initial raw offsets, encodings and so on from the entry. for (unsigned Offset = 0; Offset < Contents.size(); Offset += EntrySize) { - CompactUnwindEntry Entry(Contents.data(), Offset, Is64); + CompactUnwindEntry Entry(Contents, Offset, Is64); CompactUnwinds.push_back(Entry); } @@ -7515,19 +7528,19 @@ printMachOCompactUnwindSection(const MachOObjectFile *Obj, // __unwind_info section dumping //===----------------------------------------------------------------------===// -static void printRegularSecondLevelUnwindPage(const char *PageStart) { - const char *Pos = PageStart; - uint32_t Kind = readNext(Pos); +static void printRegularSecondLevelUnwindPage(StringRef PageData) { + ptrdiff_t Pos = 0; + uint32_t Kind = readNext(PageData, Pos); (void)Kind; assert(Kind == 2 && "kind for a regular 2nd level index should be 2"); - uint16_t EntriesStart = readNext(Pos); - uint16_t NumEntries = readNext(Pos); + uint16_t EntriesStart = readNext(PageData, Pos); + uint16_t NumEntries = readNext(PageData, Pos); - Pos = PageStart + EntriesStart; + Pos = EntriesStart; for (unsigned i = 0; i < NumEntries; ++i) { - uint32_t FunctionOffset = readNext(Pos); - uint32_t Encoding = readNext(Pos); + uint32_t FunctionOffset = readNext(PageData, Pos); + uint32_t Encoding = readNext(PageData, Pos); outs() << " [" << i << "]: " << "function offset=" << format("0x%08" PRIx32, FunctionOffset) @@ -7537,24 +7550,23 @@ static void printRegularSecondLevelUnwindPage(const char *PageStart) { } static void printCompressedSecondLevelUnwindPage( - const char *PageStart, uint32_t FunctionBase, + StringRef PageData, uint32_t FunctionBase, const SmallVectorImpl &CommonEncodings) { - const char *Pos = PageStart; - uint32_t Kind = readNext(Pos); + ptrdiff_t Pos = 0; + uint32_t Kind = readNext(PageData, Pos); (void)Kind; assert(Kind == 3 && "kind for a compressed 2nd level index should be 3"); - uint16_t EntriesStart = readNext(Pos); - uint16_t NumEntries = readNext(Pos); + uint16_t EntriesStart = readNext(PageData, Pos); + uint16_t NumEntries = readNext(PageData, Pos); - uint16_t EncodingsStart = readNext(Pos); - readNext(Pos); - const auto *PageEncodings = reinterpret_cast( - PageStart + EncodingsStart); + uint16_t EncodingsStart = readNext(PageData, Pos); + readNext(PageData, Pos); + StringRef PageEncodings = PageData.substr(EncodingsStart, StringRef::npos); - Pos = PageStart + EntriesStart; + Pos = EntriesStart; for (unsigned i = 0; i < NumEntries; ++i) { - uint32_t Entry = readNext(Pos); + uint32_t Entry = readNext(PageData, Pos); uint32_t FunctionOffset = FunctionBase + (Entry & 0xffffff); uint32_t EncodingIdx = Entry >> 24; @@ -7562,7 +7574,9 @@ static void printCompressedSecondLevelUnwindPage( if (EncodingIdx < CommonEncodings.size()) Encoding = CommonEncodings[EncodingIdx]; else - Encoding = PageEncodings[EncodingIdx - CommonEncodings.size()]; + Encoding = read(PageEncodings, + sizeof(uint32_t) * + (EncodingIdx - CommonEncodings.size())); outs() << " [" << i << "]: " << "function offset=" << format("0x%08" PRIx32, FunctionOffset) @@ -7585,13 +7599,13 @@ static void printMachOUnwindInfoSection(const MachOObjectFile *Obj, StringRef Contents; UnwindInfo.getContents(Contents); - const char *Pos = Contents.data(); + ptrdiff_t Pos = 0; //===---------------------------------- // Section header //===---------------------------------- - uint32_t Version = readNext(Pos); + uint32_t Version = readNext(Contents, Pos); outs() << " Version: " << format("0x%" PRIx32, Version) << '\n'; if (Version != 1) { @@ -7599,24 +7613,24 @@ static void printMachOUnwindInfoSection(const MachOObjectFile *Obj, return; } - uint32_t CommonEncodingsStart = readNext(Pos); + uint32_t CommonEncodingsStart = readNext(Contents, Pos); outs() << " Common encodings array section offset: " << format("0x%" PRIx32, CommonEncodingsStart) << '\n'; - uint32_t NumCommonEncodings = readNext(Pos); + uint32_t NumCommonEncodings = readNext(Contents, Pos); outs() << " Number of common encodings in array: " << format("0x%" PRIx32, NumCommonEncodings) << '\n'; - uint32_t PersonalitiesStart = readNext(Pos); + uint32_t PersonalitiesStart = readNext(Contents, Pos); outs() << " Personality function array section offset: " << format("0x%" PRIx32, PersonalitiesStart) << '\n'; - uint32_t NumPersonalities = readNext(Pos); + uint32_t NumPersonalities = readNext(Contents, Pos); outs() << " Number of personality functions in array: " << format("0x%" PRIx32, NumPersonalities) << '\n'; - uint32_t IndicesStart = readNext(Pos); + uint32_t IndicesStart = readNext(Contents, Pos); outs() << " Index array section offset: " << format("0x%" PRIx32, IndicesStart) << '\n'; - uint32_t NumIndices = readNext(Pos); + uint32_t NumIndices = readNext(Contents, Pos); outs() << " Number of indices in array: " << format("0x%" PRIx32, NumIndices) << '\n'; @@ -7631,9 +7645,9 @@ static void printMachOUnwindInfoSection(const MachOObjectFile *Obj, SmallVector CommonEncodings; outs() << " Common encodings: (count = " << NumCommonEncodings << ")\n"; - Pos = Contents.data() + CommonEncodingsStart; + Pos = CommonEncodingsStart; for (unsigned i = 0; i < NumCommonEncodings; ++i) { - uint32_t Encoding = readNext(Pos); + uint32_t Encoding = readNext(Contents, Pos); CommonEncodings.push_back(Encoding); outs() << " encoding[" << i << "]: " << format("0x%08" PRIx32, Encoding) @@ -7648,9 +7662,9 @@ static void printMachOUnwindInfoSection(const MachOObjectFile *Obj, // roughly). Particularly since they only get 2 bits in the compact encoding. outs() << " Personality functions: (count = " << NumPersonalities << ")\n"; - Pos = Contents.data() + PersonalitiesStart; + Pos = PersonalitiesStart; for (unsigned i = 0; i < NumPersonalities; ++i) { - uint32_t PersonalityFn = readNext(Pos); + uint32_t PersonalityFn = readNext(Contents, Pos); outs() << " personality[" << i + 1 << "]: " << format("0x%08" PRIx32, PersonalityFn) << '\n'; } @@ -7671,13 +7685,13 @@ static void printMachOUnwindInfoSection(const MachOObjectFile *Obj, SmallVector IndexEntries; outs() << " Top level indices: (count = " << NumIndices << ")\n"; - Pos = Contents.data() + IndicesStart; + Pos = IndicesStart; for (unsigned i = 0; i < NumIndices; ++i) { IndexEntry Entry; - Entry.FunctionOffset = readNext(Pos); - Entry.SecondLevelPageStart = readNext(Pos); - Entry.LSDAStart = readNext(Pos); + Entry.FunctionOffset = readNext(Contents, Pos); + Entry.SecondLevelPageStart = readNext(Contents, Pos); + Entry.LSDAStart = readNext(Contents, Pos); IndexEntries.push_back(Entry); outs() << " [" << i << "]: " @@ -7696,12 +7710,14 @@ static void printMachOUnwindInfoSection(const MachOObjectFile *Obj, // the first top-level index's LSDAOffset to the last (sentinel). outs() << " LSDA descriptors:\n"; - Pos = Contents.data() + IndexEntries[0].LSDAStart; - int NumLSDAs = (IndexEntries.back().LSDAStart - IndexEntries[0].LSDAStart) / - (2 * sizeof(uint32_t)); + Pos = IndexEntries[0].LSDAStart; + const uint32_t LSDASize = 2 * sizeof(uint32_t); + int NumLSDAs = + (IndexEntries.back().LSDAStart - IndexEntries[0].LSDAStart) / LSDASize; + for (int i = 0; i < NumLSDAs; ++i) { - uint32_t FunctionOffset = readNext(Pos); - uint32_t LSDAOffset = readNext(Pos); + uint32_t FunctionOffset = readNext(Contents, Pos); + uint32_t LSDAOffset = readNext(Contents, Pos); outs() << " [" << i << "]: " << "function offset=" << format("0x%08" PRIx32, FunctionOffset) << ", " @@ -7729,12 +7745,19 @@ static void printMachOUnwindInfoSection(const MachOObjectFile *Obj, << "base function offset=" << format("0x%08" PRIx32, IndexEntries[i].FunctionOffset) << '\n'; - Pos = Contents.data() + IndexEntries[i].SecondLevelPageStart; - uint32_t Kind = *reinterpret_cast(Pos); + Pos = IndexEntries[i].SecondLevelPageStart; + if (Pos + sizeof(uint32_t) > Contents.size()) { + outs() << "warning: invalid offset for second level page: " << Pos << '\n'; + continue; + } + + uint32_t Kind = + *reinterpret_cast(Contents.data() + Pos); if (Kind == 2) - printRegularSecondLevelUnwindPage(Pos); + printRegularSecondLevelUnwindPage(Contents.substr(Pos, 4096)); else if (Kind == 3) - printCompressedSecondLevelUnwindPage(Pos, IndexEntries[i].FunctionOffset, + printCompressedSecondLevelUnwindPage(Contents.substr(Pos, 4096), + IndexEntries[i].FunctionOffset, CommonEncodings); else outs() << " Skipping 2nd level page with unknown kind " << Kind