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