1 //===-- ObjDumper.cpp - Base dumper class -----------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 /// 9 /// \file 10 /// This file implements ObjDumper. 11 /// 12 //===----------------------------------------------------------------------===// 13 14 #include "ObjDumper.h" 15 #include "llvm-readobj.h" 16 #include "llvm/Object/Archive.h" 17 #include "llvm/Object/ObjectFile.h" 18 #include "llvm/Support/Error.h" 19 #include "llvm/Support/FormatVariadic.h" 20 #include "llvm/Support/ScopedPrinter.h" 21 #include "llvm/Support/raw_ostream.h" 22 #include <map> 23 24 namespace llvm { 25 26 static inline Error createError(const Twine &Msg) { 27 return createStringError(object::object_error::parse_failed, Msg); 28 } 29 30 ObjDumper::ObjDumper(ScopedPrinter &Writer, StringRef ObjName) : W(Writer) { 31 // Dumper reports all non-critical errors as warnings. 32 // It does not print the same warning more than once. 33 WarningHandler = [=](const Twine &Msg) { 34 if (Warnings.insert(Msg.str()).second) 35 reportWarning(createError(Msg), ObjName); 36 return Error::success(); 37 }; 38 } 39 40 ObjDumper::~ObjDumper() {} 41 42 void ObjDumper::reportUniqueWarning(Error Err) const { 43 reportUniqueWarning(toString(std::move(Err))); 44 } 45 46 void ObjDumper::reportUniqueWarning(const Twine &Msg) const { 47 cantFail(WarningHandler(Msg), 48 "WarningHandler should always return ErrorSuccess"); 49 } 50 51 static void printAsPrintable(raw_ostream &W, const uint8_t *Start, size_t Len) { 52 for (size_t i = 0; i < Len; i++) 53 W << (isPrint(Start[i]) ? static_cast<char>(Start[i]) : '.'); 54 } 55 56 void ObjDumper::printAsStringList(StringRef StringContent, 57 size_t StringDataOffset) { 58 size_t StrSize = StringContent.size(); 59 if (StrSize == 0) 60 return; 61 if (StrSize < StringDataOffset) { 62 reportUniqueWarning("offset (0x" + Twine::utohexstr(StringDataOffset) + 63 ") is past the end of the contents (size 0x" + 64 Twine::utohexstr(StrSize) + ")"); 65 return; 66 } 67 68 const uint8_t *StrContent = StringContent.bytes_begin(); 69 // Some formats contain additional metadata at the start which should not be 70 // interpreted as strings. Skip these bytes, but account for them in the 71 // string offsets. 72 const uint8_t *CurrentWord = StrContent + StringDataOffset; 73 const uint8_t *StrEnd = StringContent.bytes_end(); 74 75 while (CurrentWord <= StrEnd) { 76 size_t WordSize = strnlen(reinterpret_cast<const char *>(CurrentWord), 77 StrEnd - CurrentWord); 78 if (!WordSize) { 79 CurrentWord++; 80 continue; 81 } 82 W.startLine() << format("[%6tx] ", CurrentWord - StrContent); 83 printAsPrintable(W.startLine(), CurrentWord, WordSize); 84 W.startLine() << '\n'; 85 CurrentWord += WordSize + 1; 86 } 87 } 88 89 void ObjDumper::printFileSummary(StringRef FileStr, object::ObjectFile &Obj, 90 ArrayRef<std::string> InputFilenames, 91 const object::Archive *A) { 92 W.startLine() << "\n"; 93 W.printString("File", FileStr); 94 W.printString("Format", Obj.getFileFormatName()); 95 W.printString("Arch", Triple::getArchTypeName(Obj.getArch())); 96 W.printString("AddressSize", 97 std::string(formatv("{0}bit", 8 * Obj.getBytesInAddress()))); 98 this->printLoadName(); 99 } 100 101 static std::vector<object::SectionRef> 102 getSectionRefsByNameOrIndex(const object::ObjectFile &Obj, 103 ArrayRef<std::string> Sections) { 104 std::vector<object::SectionRef> Ret; 105 std::map<std::string, bool> SecNames; 106 std::map<unsigned, bool> SecIndices; 107 unsigned SecIndex; 108 for (StringRef Section : Sections) { 109 if (!Section.getAsInteger(0, SecIndex)) 110 SecIndices.emplace(SecIndex, false); 111 else 112 SecNames.emplace(std::string(Section), false); 113 } 114 115 SecIndex = Obj.isELF() ? 0 : 1; 116 for (object::SectionRef SecRef : Obj.sections()) { 117 StringRef SecName = unwrapOrError(Obj.getFileName(), SecRef.getName()); 118 auto NameIt = SecNames.find(std::string(SecName)); 119 if (NameIt != SecNames.end()) 120 NameIt->second = true; 121 auto IndexIt = SecIndices.find(SecIndex); 122 if (IndexIt != SecIndices.end()) 123 IndexIt->second = true; 124 if (NameIt != SecNames.end() || IndexIt != SecIndices.end()) 125 Ret.push_back(SecRef); 126 SecIndex++; 127 } 128 129 for (const std::pair<const std::string, bool> &S : SecNames) 130 if (!S.second) 131 reportWarning( 132 createError(formatv("could not find section '{0}'", S.first).str()), 133 Obj.getFileName()); 134 135 for (std::pair<unsigned, bool> S : SecIndices) 136 if (!S.second) 137 reportWarning( 138 createError(formatv("could not find section {0}", S.first).str()), 139 Obj.getFileName()); 140 141 return Ret; 142 } 143 144 void ObjDumper::printSectionsAsString(const object::ObjectFile &Obj, 145 ArrayRef<std::string> Sections) { 146 bool First = true; 147 for (object::SectionRef Section : 148 getSectionRefsByNameOrIndex(Obj, Sections)) { 149 StringRef SectionName = unwrapOrError(Obj.getFileName(), Section.getName()); 150 151 if (!First) 152 W.startLine() << '\n'; 153 First = false; 154 W.startLine() << "String dump of section '" << SectionName << "':\n"; 155 156 StringRef SectionContent = 157 unwrapOrError(Obj.getFileName(), Section.getContents()); 158 printAsStringList(SectionContent); 159 } 160 } 161 162 void ObjDumper::printSectionsAsHex(const object::ObjectFile &Obj, 163 ArrayRef<std::string> Sections) { 164 bool First = true; 165 for (object::SectionRef Section : 166 getSectionRefsByNameOrIndex(Obj, Sections)) { 167 StringRef SectionName = unwrapOrError(Obj.getFileName(), Section.getName()); 168 169 if (!First) 170 W.startLine() << '\n'; 171 First = false; 172 W.startLine() << "Hex dump of section '" << SectionName << "':\n"; 173 174 StringRef SectionContent = 175 unwrapOrError(Obj.getFileName(), Section.getContents()); 176 const uint8_t *SecContent = SectionContent.bytes_begin(); 177 const uint8_t *SecEnd = SecContent + SectionContent.size(); 178 179 for (const uint8_t *SecPtr = SecContent; SecPtr < SecEnd; SecPtr += 16) { 180 const uint8_t *TmpSecPtr = SecPtr; 181 uint8_t i; 182 uint8_t k; 183 184 W.startLine() << format_hex(Section.getAddress() + (SecPtr - SecContent), 185 10); 186 W.startLine() << ' '; 187 for (i = 0; TmpSecPtr < SecEnd && i < 4; ++i) { 188 for (k = 0; TmpSecPtr < SecEnd && k < 4; k++, TmpSecPtr++) { 189 uint8_t Val = *(reinterpret_cast<const uint8_t *>(TmpSecPtr)); 190 W.startLine() << format_hex_no_prefix(Val, 2); 191 } 192 W.startLine() << ' '; 193 } 194 195 // We need to print the correct amount of spaces to match the format. 196 // We are adding the (4 - i) last rows that are 8 characters each. 197 // Then, the (4 - i) spaces that are in between the rows. 198 // Least, if we cut in a middle of a row, we add the remaining characters, 199 // which is (8 - (k * 2)). 200 if (i < 4) 201 W.startLine() << format("%*c", (4 - i) * 8 + (4 - i), ' '); 202 if (k < 4) 203 W.startLine() << format("%*c", 8 - k * 2, ' '); 204 205 TmpSecPtr = SecPtr; 206 for (i = 0; TmpSecPtr + i < SecEnd && i < 16; ++i) 207 W.startLine() << (isPrint(TmpSecPtr[i]) 208 ? static_cast<char>(TmpSecPtr[i]) 209 : '.'); 210 211 W.startLine() << '\n'; 212 } 213 } 214 } 215 216 } // namespace llvm 217