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