ObjDumper.cpp 7.5 KB

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