10b57cec5SDimitry Andric //===-- ObjDumper.cpp - Base dumper class -----------------------*- C++ -*-===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric /// 90b57cec5SDimitry Andric /// \file 100b57cec5SDimitry Andric /// This file implements ObjDumper. 110b57cec5SDimitry Andric /// 120b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 130b57cec5SDimitry Andric 140b57cec5SDimitry Andric #include "ObjDumper.h" 150b57cec5SDimitry Andric #include "llvm-readobj.h" 160eae32dcSDimitry Andric #include "llvm/Object/Archive.h" 174c2d3b02SDimitry Andric #include "llvm/Object/Decompressor.h" 180b57cec5SDimitry Andric #include "llvm/Object/ObjectFile.h" 190b57cec5SDimitry Andric #include "llvm/Support/Error.h" 200b57cec5SDimitry Andric #include "llvm/Support/FormatVariadic.h" 210b57cec5SDimitry Andric #include "llvm/Support/ScopedPrinter.h" 225f757f3fSDimitry Andric #include "llvm/Support/SystemZ/zOSSupport.h" 230b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 240b57cec5SDimitry Andric #include <map> 250b57cec5SDimitry Andric 260b57cec5SDimitry Andric namespace llvm { 270b57cec5SDimitry Andric 288bcb0991SDimitry Andric static inline Error createError(const Twine &Msg) { 298bcb0991SDimitry Andric return createStringError(object::object_error::parse_failed, Msg); 308bcb0991SDimitry Andric } 318bcb0991SDimitry Andric 32e8d8bef9SDimitry Andric ObjDumper::ObjDumper(ScopedPrinter &Writer, StringRef ObjName) : W(Writer) { 33e8d8bef9SDimitry Andric // Dumper reports all non-critical errors as warnings. 34e8d8bef9SDimitry Andric // It does not print the same warning more than once. 35e8d8bef9SDimitry Andric WarningHandler = [=](const Twine &Msg) { 36e8d8bef9SDimitry Andric if (Warnings.insert(Msg.str()).second) 37e8d8bef9SDimitry Andric reportWarning(createError(Msg), ObjName); 38e8d8bef9SDimitry Andric return Error::success(); 39e8d8bef9SDimitry Andric }; 40e8d8bef9SDimitry Andric } 410b57cec5SDimitry Andric 42e8d8bef9SDimitry Andric ObjDumper::~ObjDumper() {} 43e8d8bef9SDimitry Andric 44e8d8bef9SDimitry Andric void ObjDumper::reportUniqueWarning(Error Err) const { 45e8d8bef9SDimitry Andric reportUniqueWarning(toString(std::move(Err))); 46e8d8bef9SDimitry Andric } 47e8d8bef9SDimitry Andric 48e8d8bef9SDimitry Andric void ObjDumper::reportUniqueWarning(const Twine &Msg) const { 49e8d8bef9SDimitry Andric cantFail(WarningHandler(Msg), 50e8d8bef9SDimitry Andric "WarningHandler should always return ErrorSuccess"); 510b57cec5SDimitry Andric } 520b57cec5SDimitry Andric 530b57cec5SDimitry Andric static void printAsPrintable(raw_ostream &W, const uint8_t *Start, size_t Len) { 540b57cec5SDimitry Andric for (size_t i = 0; i < Len; i++) 550b57cec5SDimitry Andric W << (isPrint(Start[i]) ? static_cast<char>(Start[i]) : '.'); 560b57cec5SDimitry Andric } 570b57cec5SDimitry Andric 58349cc55cSDimitry Andric void ObjDumper::printAsStringList(StringRef StringContent, 59349cc55cSDimitry Andric size_t StringDataOffset) { 60349cc55cSDimitry Andric size_t StrSize = StringContent.size(); 61349cc55cSDimitry Andric if (StrSize == 0) 62349cc55cSDimitry Andric return; 63349cc55cSDimitry Andric if (StrSize < StringDataOffset) { 64349cc55cSDimitry Andric reportUniqueWarning("offset (0x" + Twine::utohexstr(StringDataOffset) + 65349cc55cSDimitry Andric ") is past the end of the contents (size 0x" + 66349cc55cSDimitry Andric Twine::utohexstr(StrSize) + ")"); 67349cc55cSDimitry Andric return; 68349cc55cSDimitry Andric } 69349cc55cSDimitry Andric 70fe6060f1SDimitry Andric const uint8_t *StrContent = StringContent.bytes_begin(); 71349cc55cSDimitry Andric // Some formats contain additional metadata at the start which should not be 72349cc55cSDimitry Andric // interpreted as strings. Skip these bytes, but account for them in the 73349cc55cSDimitry Andric // string offsets. 74349cc55cSDimitry Andric const uint8_t *CurrentWord = StrContent + StringDataOffset; 75fe6060f1SDimitry Andric const uint8_t *StrEnd = StringContent.bytes_end(); 76fe6060f1SDimitry Andric 77fe6060f1SDimitry Andric while (CurrentWord <= StrEnd) { 78fe6060f1SDimitry Andric size_t WordSize = strnlen(reinterpret_cast<const char *>(CurrentWord), 79fe6060f1SDimitry Andric StrEnd - CurrentWord); 80fe6060f1SDimitry Andric if (!WordSize) { 81fe6060f1SDimitry Andric CurrentWord++; 82fe6060f1SDimitry Andric continue; 83fe6060f1SDimitry Andric } 84fe6060f1SDimitry Andric W.startLine() << format("[%6tx] ", CurrentWord - StrContent); 85fe6060f1SDimitry Andric printAsPrintable(W.startLine(), CurrentWord, WordSize); 86fe6060f1SDimitry Andric W.startLine() << '\n'; 87fe6060f1SDimitry Andric CurrentWord += WordSize + 1; 88fe6060f1SDimitry Andric } 89fe6060f1SDimitry Andric } 90fe6060f1SDimitry Andric 910eae32dcSDimitry Andric void ObjDumper::printFileSummary(StringRef FileStr, object::ObjectFile &Obj, 920eae32dcSDimitry Andric ArrayRef<std::string> InputFilenames, 930eae32dcSDimitry Andric const object::Archive *A) { 940eae32dcSDimitry Andric W.startLine() << "\n"; 950eae32dcSDimitry Andric W.printString("File", FileStr); 960eae32dcSDimitry Andric W.printString("Format", Obj.getFileFormatName()); 970eae32dcSDimitry Andric W.printString("Arch", Triple::getArchTypeName(Obj.getArch())); 980eae32dcSDimitry Andric W.printString("AddressSize", 990eae32dcSDimitry Andric std::string(formatv("{0}bit", 8 * Obj.getBytesInAddress()))); 1000eae32dcSDimitry Andric this->printLoadName(); 1010eae32dcSDimitry Andric } 1020eae32dcSDimitry Andric 1030b57cec5SDimitry Andric static std::vector<object::SectionRef> 104e8d8bef9SDimitry Andric getSectionRefsByNameOrIndex(const object::ObjectFile &Obj, 1050b57cec5SDimitry Andric ArrayRef<std::string> Sections) { 1060b57cec5SDimitry Andric std::vector<object::SectionRef> Ret; 1070b57cec5SDimitry Andric std::map<std::string, bool> SecNames; 1080b57cec5SDimitry Andric std::map<unsigned, bool> SecIndices; 1090b57cec5SDimitry Andric unsigned SecIndex; 1100b57cec5SDimitry Andric for (StringRef Section : Sections) { 1110b57cec5SDimitry Andric if (!Section.getAsInteger(0, SecIndex)) 1120b57cec5SDimitry Andric SecIndices.emplace(SecIndex, false); 1130b57cec5SDimitry Andric else 1145ffd83dbSDimitry Andric SecNames.emplace(std::string(Section), false); 1150b57cec5SDimitry Andric } 1160b57cec5SDimitry Andric 117e8d8bef9SDimitry Andric SecIndex = Obj.isELF() ? 0 : 1; 118e8d8bef9SDimitry Andric for (object::SectionRef SecRef : Obj.sections()) { 119e8d8bef9SDimitry Andric StringRef SecName = unwrapOrError(Obj.getFileName(), SecRef.getName()); 1205ffd83dbSDimitry Andric auto NameIt = SecNames.find(std::string(SecName)); 1210b57cec5SDimitry Andric if (NameIt != SecNames.end()) 1220b57cec5SDimitry Andric NameIt->second = true; 1230b57cec5SDimitry Andric auto IndexIt = SecIndices.find(SecIndex); 1240b57cec5SDimitry Andric if (IndexIt != SecIndices.end()) 1250b57cec5SDimitry Andric IndexIt->second = true; 1260b57cec5SDimitry Andric if (NameIt != SecNames.end() || IndexIt != SecIndices.end()) 1270b57cec5SDimitry Andric Ret.push_back(SecRef); 1280b57cec5SDimitry Andric SecIndex++; 1290b57cec5SDimitry Andric } 1300b57cec5SDimitry Andric 131480093f4SDimitry Andric for (const std::pair<const std::string, bool> &S : SecNames) 1320b57cec5SDimitry Andric if (!S.second) 1338bcb0991SDimitry Andric reportWarning( 1348bcb0991SDimitry Andric createError(formatv("could not find section '{0}'", S.first).str()), 135e8d8bef9SDimitry Andric Obj.getFileName()); 1368bcb0991SDimitry Andric 1370b57cec5SDimitry Andric for (std::pair<unsigned, bool> S : SecIndices) 1380b57cec5SDimitry Andric if (!S.second) 1398bcb0991SDimitry Andric reportWarning( 1408bcb0991SDimitry Andric createError(formatv("could not find section {0}", S.first).str()), 141e8d8bef9SDimitry Andric Obj.getFileName()); 1420b57cec5SDimitry Andric 1430b57cec5SDimitry Andric return Ret; 1440b57cec5SDimitry Andric } 1450b57cec5SDimitry Andric 1464c2d3b02SDimitry Andric static void maybeDecompress(const object::ObjectFile &Obj, 1474c2d3b02SDimitry Andric StringRef SectionName, StringRef &SectionContent, 1484c2d3b02SDimitry Andric SmallString<0> &Out) { 1494c2d3b02SDimitry Andric Expected<object::Decompressor> Decompressor = object::Decompressor::create( 1504c2d3b02SDimitry Andric SectionName, SectionContent, Obj.isLittleEndian(), Obj.is64Bit()); 1514c2d3b02SDimitry Andric if (!Decompressor) 1524c2d3b02SDimitry Andric reportWarning(Decompressor.takeError(), Obj.getFileName()); 1534c2d3b02SDimitry Andric else if (auto Err = Decompressor->resizeAndDecompress(Out)) 1544c2d3b02SDimitry Andric reportWarning(std::move(Err), Obj.getFileName()); 1554c2d3b02SDimitry Andric else 1564c2d3b02SDimitry Andric SectionContent = Out; 1574c2d3b02SDimitry Andric } 1584c2d3b02SDimitry Andric 159e8d8bef9SDimitry Andric void ObjDumper::printSectionsAsString(const object::ObjectFile &Obj, 1604c2d3b02SDimitry Andric ArrayRef<std::string> Sections, 1614c2d3b02SDimitry Andric bool Decompress) { 1624c2d3b02SDimitry Andric SmallString<0> Out; 1630b57cec5SDimitry Andric for (object::SectionRef Section : 1640b57cec5SDimitry Andric getSectionRefsByNameOrIndex(Obj, Sections)) { 165e8d8bef9SDimitry Andric StringRef SectionName = unwrapOrError(Obj.getFileName(), Section.getName()); 166*0fca6ea1SDimitry Andric W.startLine() << "\nString dump of section '" << SectionName << "':\n"; 1670b57cec5SDimitry Andric 1688bcb0991SDimitry Andric StringRef SectionContent = 169e8d8bef9SDimitry Andric unwrapOrError(Obj.getFileName(), Section.getContents()); 1704c2d3b02SDimitry Andric if (Decompress && Section.isCompressed()) 1714c2d3b02SDimitry Andric maybeDecompress(Obj, SectionName, SectionContent, Out); 172fe6060f1SDimitry Andric printAsStringList(SectionContent); 1730b57cec5SDimitry Andric } 1740b57cec5SDimitry Andric } 1750b57cec5SDimitry Andric 176e8d8bef9SDimitry Andric void ObjDumper::printSectionsAsHex(const object::ObjectFile &Obj, 1774c2d3b02SDimitry Andric ArrayRef<std::string> Sections, 1784c2d3b02SDimitry Andric bool Decompress) { 1794c2d3b02SDimitry Andric SmallString<0> Out; 1800b57cec5SDimitry Andric for (object::SectionRef Section : 1810b57cec5SDimitry Andric getSectionRefsByNameOrIndex(Obj, Sections)) { 182e8d8bef9SDimitry Andric StringRef SectionName = unwrapOrError(Obj.getFileName(), Section.getName()); 183*0fca6ea1SDimitry Andric W.startLine() << "\nHex dump of section '" << SectionName << "':\n"; 1840b57cec5SDimitry Andric 1858bcb0991SDimitry Andric StringRef SectionContent = 186e8d8bef9SDimitry Andric unwrapOrError(Obj.getFileName(), Section.getContents()); 1874c2d3b02SDimitry Andric if (Decompress && Section.isCompressed()) 1884c2d3b02SDimitry Andric maybeDecompress(Obj, SectionName, SectionContent, Out); 1890b57cec5SDimitry Andric const uint8_t *SecContent = SectionContent.bytes_begin(); 1900b57cec5SDimitry Andric const uint8_t *SecEnd = SecContent + SectionContent.size(); 1910b57cec5SDimitry Andric 1920b57cec5SDimitry Andric for (const uint8_t *SecPtr = SecContent; SecPtr < SecEnd; SecPtr += 16) { 1930b57cec5SDimitry Andric const uint8_t *TmpSecPtr = SecPtr; 1940b57cec5SDimitry Andric uint8_t i; 1950b57cec5SDimitry Andric uint8_t k; 1960b57cec5SDimitry Andric 1970b57cec5SDimitry Andric W.startLine() << format_hex(Section.getAddress() + (SecPtr - SecContent), 1980b57cec5SDimitry Andric 10); 1990b57cec5SDimitry Andric W.startLine() << ' '; 2000b57cec5SDimitry Andric for (i = 0; TmpSecPtr < SecEnd && i < 4; ++i) { 2010b57cec5SDimitry Andric for (k = 0; TmpSecPtr < SecEnd && k < 4; k++, TmpSecPtr++) { 2020b57cec5SDimitry Andric uint8_t Val = *(reinterpret_cast<const uint8_t *>(TmpSecPtr)); 2030b57cec5SDimitry Andric W.startLine() << format_hex_no_prefix(Val, 2); 2040b57cec5SDimitry Andric } 2050b57cec5SDimitry Andric W.startLine() << ' '; 2060b57cec5SDimitry Andric } 2070b57cec5SDimitry Andric 2080b57cec5SDimitry Andric // We need to print the correct amount of spaces to match the format. 2090b57cec5SDimitry Andric // We are adding the (4 - i) last rows that are 8 characters each. 2100b57cec5SDimitry Andric // Then, the (4 - i) spaces that are in between the rows. 2110b57cec5SDimitry Andric // Least, if we cut in a middle of a row, we add the remaining characters, 2120b57cec5SDimitry Andric // which is (8 - (k * 2)). 2130b57cec5SDimitry Andric if (i < 4) 214e8d8bef9SDimitry Andric W.startLine() << format("%*c", (4 - i) * 8 + (4 - i), ' '); 215e8d8bef9SDimitry Andric if (k < 4) 216e8d8bef9SDimitry Andric W.startLine() << format("%*c", 8 - k * 2, ' '); 2170b57cec5SDimitry Andric 2180b57cec5SDimitry Andric TmpSecPtr = SecPtr; 2190b57cec5SDimitry Andric for (i = 0; TmpSecPtr + i < SecEnd && i < 16; ++i) 2200b57cec5SDimitry Andric W.startLine() << (isPrint(TmpSecPtr[i]) 2210b57cec5SDimitry Andric ? static_cast<char>(TmpSecPtr[i]) 2220b57cec5SDimitry Andric : '.'); 2230b57cec5SDimitry Andric 2240b57cec5SDimitry Andric W.startLine() << '\n'; 2250b57cec5SDimitry Andric } 2260b57cec5SDimitry Andric } 2270b57cec5SDimitry Andric } 2280b57cec5SDimitry Andric 2290b57cec5SDimitry Andric } // namespace llvm 230