xref: /freebsd/contrib/llvm-project/llvm/tools/llvm-readobj/ObjDumper.cpp (revision 5e801ac66d24704442eba426ed13c3effb8a34e7)
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                                   size_t StringDataOffset) {
57   size_t StrSize = StringContent.size();
58   if (StrSize == 0)
59     return;
60   if (StrSize < StringDataOffset) {
61     reportUniqueWarning("offset (0x" + Twine::utohexstr(StringDataOffset) +
62                         ") is past the end of the contents (size 0x" +
63                         Twine::utohexstr(StrSize) + ")");
64     return;
65   }
66 
67   const uint8_t *StrContent = StringContent.bytes_begin();
68   // Some formats contain additional metadata at the start which should not be
69   // interpreted as strings. Skip these bytes, but account for them in the
70   // string offsets.
71   const uint8_t *CurrentWord = StrContent + StringDataOffset;
72   const uint8_t *StrEnd = StringContent.bytes_end();
73 
74   while (CurrentWord <= StrEnd) {
75     size_t WordSize = strnlen(reinterpret_cast<const char *>(CurrentWord),
76                               StrEnd - CurrentWord);
77     if (!WordSize) {
78       CurrentWord++;
79       continue;
80     }
81     W.startLine() << format("[%6tx] ", CurrentWord - StrContent);
82     printAsPrintable(W.startLine(), CurrentWord, WordSize);
83     W.startLine() << '\n';
84     CurrentWord += WordSize + 1;
85   }
86 }
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 
102   SecIndex = Obj.isELF() ? 0 : 1;
103   for (object::SectionRef SecRef : Obj.sections()) {
104     StringRef SecName = unwrapOrError(Obj.getFileName(), SecRef.getName());
105     auto NameIt = SecNames.find(std::string(SecName));
106     if (NameIt != SecNames.end())
107       NameIt->second = true;
108     auto IndexIt = SecIndices.find(SecIndex);
109     if (IndexIt != SecIndices.end())
110       IndexIt->second = true;
111     if (NameIt != SecNames.end() || IndexIt != SecIndices.end())
112       Ret.push_back(SecRef);
113     SecIndex++;
114   }
115 
116   for (const std::pair<const std::string, bool> &S : SecNames)
117     if (!S.second)
118       reportWarning(
119           createError(formatv("could not find section '{0}'", S.first).str()),
120           Obj.getFileName());
121 
122   for (std::pair<unsigned, bool> S : SecIndices)
123     if (!S.second)
124       reportWarning(
125           createError(formatv("could not find section {0}", S.first).str()),
126           Obj.getFileName());
127 
128   return Ret;
129 }
130 
131 void ObjDumper::printSectionsAsString(const object::ObjectFile &Obj,
132                                       ArrayRef<std::string> Sections) {
133   bool First = true;
134   for (object::SectionRef Section :
135        getSectionRefsByNameOrIndex(Obj, Sections)) {
136     StringRef SectionName = unwrapOrError(Obj.getFileName(), Section.getName());
137 
138     if (!First)
139       W.startLine() << '\n';
140     First = false;
141     W.startLine() << "String dump of section '" << SectionName << "':\n";
142 
143     StringRef SectionContent =
144         unwrapOrError(Obj.getFileName(), Section.getContents());
145     printAsStringList(SectionContent);
146   }
147 }
148 
149 void ObjDumper::printSectionsAsHex(const object::ObjectFile &Obj,
150                                    ArrayRef<std::string> Sections) {
151   bool First = true;
152   for (object::SectionRef Section :
153        getSectionRefsByNameOrIndex(Obj, Sections)) {
154     StringRef SectionName = unwrapOrError(Obj.getFileName(), Section.getName());
155 
156     if (!First)
157       W.startLine() << '\n';
158     First = false;
159     W.startLine() << "Hex dump of section '" << SectionName << "':\n";
160 
161     StringRef SectionContent =
162         unwrapOrError(Obj.getFileName(), Section.getContents());
163     const uint8_t *SecContent = SectionContent.bytes_begin();
164     const uint8_t *SecEnd = SecContent + SectionContent.size();
165 
166     for (const uint8_t *SecPtr = SecContent; SecPtr < SecEnd; SecPtr += 16) {
167       const uint8_t *TmpSecPtr = SecPtr;
168       uint8_t i;
169       uint8_t k;
170 
171       W.startLine() << format_hex(Section.getAddress() + (SecPtr - SecContent),
172                                   10);
173       W.startLine() << ' ';
174       for (i = 0; TmpSecPtr < SecEnd && i < 4; ++i) {
175         for (k = 0; TmpSecPtr < SecEnd && k < 4; k++, TmpSecPtr++) {
176           uint8_t Val = *(reinterpret_cast<const uint8_t *>(TmpSecPtr));
177           W.startLine() << format_hex_no_prefix(Val, 2);
178         }
179         W.startLine() << ' ';
180       }
181 
182       // We need to print the correct amount of spaces to match the format.
183       // We are adding the (4 - i) last rows that are 8 characters each.
184       // Then, the (4 - i) spaces that are in between the rows.
185       // Least, if we cut in a middle of a row, we add the remaining characters,
186       // which is (8 - (k * 2)).
187       if (i < 4)
188         W.startLine() << format("%*c", (4 - i) * 8 + (4 - i), ' ');
189       if (k < 4)
190         W.startLine() << format("%*c", 8 - k * 2, ' ');
191 
192       TmpSecPtr = SecPtr;
193       for (i = 0; TmpSecPtr + i < SecEnd && i < 16; ++i)
194         W.startLine() << (isPrint(TmpSecPtr[i])
195                               ? static_cast<char>(TmpSecPtr[i])
196                               : '.');
197 
198       W.startLine() << '\n';
199     }
200   }
201 }
202 
203 } // namespace llvm
204