1 //===-- ObjDumper.cpp - Base dumper class -----------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
10 /// This file implements ObjDumper.
12 //===----------------------------------------------------------------------===//
14 #include "ObjDumper.h"
15 #include "llvm-readobj.h"
16 #include "llvm/Object/Archive.h"
17 #include "llvm/Object/Decompressor.h"
18 #include "llvm/Object/ObjectFile.h"
19 #include "llvm/Support/Error.h"
20 #include "llvm/Support/FormatVariadic.h"
21 #include "llvm/Support/ScopedPrinter.h"
22 #include "llvm/Support/SystemZ/zOSSupport.h"
23 #include "llvm/Support/raw_ostream.h"
28 static inline Error
createError(const Twine
&Msg
) {
29 return createStringError(object::object_error::parse_failed
, Msg
);
32 ObjDumper::ObjDumper(ScopedPrinter
&Writer
, StringRef ObjName
) : W(Writer
) {
33 // Dumper reports all non-critical errors as warnings.
34 // It does not print the same warning more than once.
35 WarningHandler
= [=](const Twine
&Msg
) {
36 if (Warnings
.insert(Msg
.str()).second
)
37 reportWarning(createError(Msg
), ObjName
);
38 return Error::success();
42 ObjDumper::~ObjDumper() {}
44 void ObjDumper::reportUniqueWarning(Error Err
) const {
45 reportUniqueWarning(toString(std::move(Err
)));
48 void ObjDumper::reportUniqueWarning(const Twine
&Msg
) const {
49 cantFail(WarningHandler(Msg
),
50 "WarningHandler should always return ErrorSuccess");
53 static void printAsPrintable(raw_ostream
&W
, const uint8_t *Start
, size_t Len
) {
54 for (size_t i
= 0; i
< Len
; i
++)
55 W
<< (isPrint(Start
[i
]) ? static_cast<char>(Start
[i
]) : '.');
58 void ObjDumper::printAsStringList(StringRef StringContent
,
59 size_t StringDataOffset
) {
60 size_t StrSize
= StringContent
.size();
63 if (StrSize
< StringDataOffset
) {
64 reportUniqueWarning("offset (0x" + Twine::utohexstr(StringDataOffset
) +
65 ") is past the end of the contents (size 0x" +
66 Twine::utohexstr(StrSize
) + ")");
70 const uint8_t *StrContent
= StringContent
.bytes_begin();
71 // Some formats contain additional metadata at the start which should not be
72 // interpreted as strings. Skip these bytes, but account for them in the
74 const uint8_t *CurrentWord
= StrContent
+ StringDataOffset
;
75 const uint8_t *StrEnd
= StringContent
.bytes_end();
77 while (CurrentWord
<= StrEnd
) {
78 size_t WordSize
= strnlen(reinterpret_cast<const char *>(CurrentWord
),
79 StrEnd
- CurrentWord
);
84 W
.startLine() << format("[%6tx] ", CurrentWord
- StrContent
);
85 printAsPrintable(W
.startLine(), CurrentWord
, WordSize
);
86 W
.startLine() << '\n';
87 CurrentWord
+= WordSize
+ 1;
91 void ObjDumper::printFileSummary(StringRef FileStr
, object::ObjectFile
&Obj
,
92 ArrayRef
<std::string
> InputFilenames
,
93 const object::Archive
*A
) {
94 W
.startLine() << "\n";
95 W
.printString("File", FileStr
);
96 W
.printString("Format", Obj
.getFileFormatName());
97 W
.printString("Arch", Triple::getArchTypeName(Obj
.getArch()));
98 W
.printString("AddressSize",
99 std::string(formatv("{0}bit", 8 * Obj
.getBytesInAddress())));
100 this->printLoadName();
103 static std::vector
<object::SectionRef
>
104 getSectionRefsByNameOrIndex(const object::ObjectFile
&Obj
,
105 ArrayRef
<std::string
> Sections
) {
106 std::vector
<object::SectionRef
> Ret
;
107 std::map
<std::string
, bool> SecNames
;
108 std::map
<unsigned, bool> SecIndices
;
110 for (StringRef Section
: Sections
) {
111 if (!Section
.getAsInteger(0, SecIndex
))
112 SecIndices
.emplace(SecIndex
, false);
114 SecNames
.emplace(std::string(Section
), false);
117 SecIndex
= Obj
.isELF() ? 0 : 1;
118 for (object::SectionRef SecRef
: Obj
.sections()) {
119 StringRef SecName
= unwrapOrError(Obj
.getFileName(), SecRef
.getName());
120 auto NameIt
= SecNames
.find(std::string(SecName
));
121 if (NameIt
!= SecNames
.end())
122 NameIt
->second
= true;
123 auto IndexIt
= SecIndices
.find(SecIndex
);
124 if (IndexIt
!= SecIndices
.end())
125 IndexIt
->second
= true;
126 if (NameIt
!= SecNames
.end() || IndexIt
!= SecIndices
.end())
127 Ret
.push_back(SecRef
);
131 for (const std::pair
<const std::string
, bool> &S
: SecNames
)
134 createError(formatv("could not find section '{0}'", S
.first
).str()),
137 for (std::pair
<unsigned, bool> S
: SecIndices
)
140 createError(formatv("could not find section {0}", S
.first
).str()),
146 static void maybeDecompress(const object::ObjectFile
&Obj
,
147 StringRef SectionName
, StringRef
&SectionContent
,
148 SmallString
<0> &Out
) {
149 Expected
<object::Decompressor
> Decompressor
= object::Decompressor::create(
150 SectionName
, SectionContent
, Obj
.isLittleEndian(), Obj
.is64Bit());
152 reportWarning(Decompressor
.takeError(), Obj
.getFileName());
153 else if (auto Err
= Decompressor
->resizeAndDecompress(Out
))
154 reportWarning(std::move(Err
), Obj
.getFileName());
156 SectionContent
= Out
;
159 void ObjDumper::printSectionsAsString(const object::ObjectFile
&Obj
,
160 ArrayRef
<std::string
> Sections
,
164 for (object::SectionRef Section
:
165 getSectionRefsByNameOrIndex(Obj
, Sections
)) {
166 StringRef SectionName
= unwrapOrError(Obj
.getFileName(), Section
.getName());
169 W
.startLine() << '\n';
171 W
.startLine() << "String dump of section '" << SectionName
<< "':\n";
173 StringRef SectionContent
=
174 unwrapOrError(Obj
.getFileName(), Section
.getContents());
175 if (Decompress
&& Section
.isCompressed())
176 maybeDecompress(Obj
, SectionName
, SectionContent
, Out
);
177 printAsStringList(SectionContent
);
181 void ObjDumper::printSectionsAsHex(const object::ObjectFile
&Obj
,
182 ArrayRef
<std::string
> Sections
,
186 for (object::SectionRef Section
:
187 getSectionRefsByNameOrIndex(Obj
, Sections
)) {
188 StringRef SectionName
= unwrapOrError(Obj
.getFileName(), Section
.getName());
191 W
.startLine() << '\n';
193 W
.startLine() << "Hex dump of section '" << SectionName
<< "':\n";
195 StringRef SectionContent
=
196 unwrapOrError(Obj
.getFileName(), Section
.getContents());
197 if (Decompress
&& Section
.isCompressed())
198 maybeDecompress(Obj
, SectionName
, SectionContent
, Out
);
199 const uint8_t *SecContent
= SectionContent
.bytes_begin();
200 const uint8_t *SecEnd
= SecContent
+ SectionContent
.size();
202 for (const uint8_t *SecPtr
= SecContent
; SecPtr
< SecEnd
; SecPtr
+= 16) {
203 const uint8_t *TmpSecPtr
= SecPtr
;
207 W
.startLine() << format_hex(Section
.getAddress() + (SecPtr
- SecContent
),
209 W
.startLine() << ' ';
210 for (i
= 0; TmpSecPtr
< SecEnd
&& i
< 4; ++i
) {
211 for (k
= 0; TmpSecPtr
< SecEnd
&& k
< 4; k
++, TmpSecPtr
++) {
212 uint8_t Val
= *(reinterpret_cast<const uint8_t *>(TmpSecPtr
));
213 W
.startLine() << format_hex_no_prefix(Val
, 2);
215 W
.startLine() << ' ';
218 // We need to print the correct amount of spaces to match the format.
219 // We are adding the (4 - i) last rows that are 8 characters each.
220 // Then, the (4 - i) spaces that are in between the rows.
221 // Least, if we cut in a middle of a row, we add the remaining characters,
222 // which is (8 - (k * 2)).
224 W
.startLine() << format("%*c", (4 - i
) * 8 + (4 - i
), ' ');
226 W
.startLine() << format("%*c", 8 - k
* 2, ' ');
229 for (i
= 0; TmpSecPtr
+ i
< SecEnd
&& i
< 16; ++i
)
230 W
.startLine() << (isPrint(TmpSecPtr
[i
])
231 ? static_cast<char>(TmpSecPtr
[i
])
234 W
.startLine() << '\n';