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
.getOStream(), CurrentWord
, WordSize
);
86 W
.getOStream() << '\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 if (!FileStr
.empty()) {
95 W
.getOStream() << "\n";
96 W
.printString("File", FileStr
);
98 W
.printString("Format", Obj
.getFileFormatName());
99 W
.printString("Arch", Triple::getArchTypeName(Obj
.getArch()));
100 W
.printString("AddressSize",
101 std::string(formatv("{0}bit", 8 * Obj
.getBytesInAddress())));
102 this->printLoadName();
105 static std::vector
<object::SectionRef
>
106 getSectionRefsByNameOrIndex(const object::ObjectFile
&Obj
,
107 ArrayRef
<std::string
> Sections
) {
108 std::vector
<object::SectionRef
> Ret
;
109 std::map
<std::string
, bool, std::less
<>> SecNames
;
110 std::map
<unsigned, bool> SecIndices
;
112 for (StringRef Section
: Sections
) {
113 if (!Section
.getAsInteger(0, SecIndex
))
114 SecIndices
.emplace(SecIndex
, false);
116 SecNames
.emplace(std::string(Section
), false);
119 SecIndex
= Obj
.isELF() ? 0 : 1;
120 for (object::SectionRef SecRef
: Obj
.sections()) {
121 StringRef SecName
= unwrapOrError(Obj
.getFileName(), SecRef
.getName());
122 auto NameIt
= SecNames
.find(SecName
);
123 if (NameIt
!= SecNames
.end())
124 NameIt
->second
= true;
125 auto IndexIt
= SecIndices
.find(SecIndex
);
126 if (IndexIt
!= SecIndices
.end())
127 IndexIt
->second
= true;
128 if (NameIt
!= SecNames
.end() || IndexIt
!= SecIndices
.end())
129 Ret
.push_back(SecRef
);
133 for (const std::pair
<const std::string
, bool> &S
: SecNames
)
136 createError(formatv("could not find section '{0}'", S
.first
).str()),
139 for (std::pair
<unsigned, bool> S
: SecIndices
)
142 createError(formatv("could not find section {0}", S
.first
).str()),
148 static void maybeDecompress(const object::ObjectFile
&Obj
,
149 StringRef SectionName
, StringRef
&SectionContent
,
150 SmallString
<0> &Out
) {
151 Expected
<object::Decompressor
> Decompressor
= object::Decompressor::create(
152 SectionName
, SectionContent
, Obj
.isLittleEndian(), Obj
.is64Bit());
154 reportWarning(Decompressor
.takeError(), Obj
.getFileName());
155 else if (auto Err
= Decompressor
->resizeAndDecompress(Out
))
156 reportWarning(std::move(Err
), Obj
.getFileName());
158 SectionContent
= Out
;
161 void ObjDumper::printSectionsAsString(const object::ObjectFile
&Obj
,
162 ArrayRef
<std::string
> Sections
,
165 for (object::SectionRef Section
:
166 getSectionRefsByNameOrIndex(Obj
, Sections
)) {
167 StringRef SectionName
= unwrapOrError(Obj
.getFileName(), Section
.getName());
168 W
.getOStream() << '\n';
169 W
.startLine() << "String dump of section '" << SectionName
<< "':\n";
171 StringRef SectionContent
=
172 unwrapOrError(Obj
.getFileName(), Section
.getContents());
173 if (Decompress
&& Section
.isCompressed())
174 maybeDecompress(Obj
, SectionName
, SectionContent
, Out
);
175 printAsStringList(SectionContent
);
179 void ObjDumper::printSectionsAsHex(const object::ObjectFile
&Obj
,
180 ArrayRef
<std::string
> Sections
,
183 for (object::SectionRef Section
:
184 getSectionRefsByNameOrIndex(Obj
, Sections
)) {
185 StringRef SectionName
= unwrapOrError(Obj
.getFileName(), Section
.getName());
186 W
.getOStream() << '\n';
187 W
.startLine() << "Hex dump of section '" << SectionName
<< "':\n";
189 StringRef SectionContent
=
190 unwrapOrError(Obj
.getFileName(), Section
.getContents());
191 if (Decompress
&& Section
.isCompressed())
192 maybeDecompress(Obj
, SectionName
, SectionContent
, Out
);
193 const uint8_t *SecContent
= SectionContent
.bytes_begin();
194 const uint8_t *SecEnd
= SecContent
+ SectionContent
.size();
196 for (const uint8_t *SecPtr
= SecContent
; SecPtr
< SecEnd
; SecPtr
+= 16) {
197 const uint8_t *TmpSecPtr
= SecPtr
;
201 W
.startLine() << format_hex(Section
.getAddress() + (SecPtr
- SecContent
),
203 W
.getOStream() << ' ';
204 for (i
= 0; TmpSecPtr
< SecEnd
&& i
< 4; ++i
) {
205 for (k
= 0; TmpSecPtr
< SecEnd
&& k
< 4; k
++, TmpSecPtr
++) {
206 uint8_t Val
= *(reinterpret_cast<const uint8_t *>(TmpSecPtr
));
207 W
.getOStream() << format_hex_no_prefix(Val
, 2);
209 W
.getOStream() << ' ';
212 // We need to print the correct amount of spaces to match the format.
213 // We are adding the (4 - i) last rows that are 8 characters each.
214 // Then, the (4 - i) spaces that are in between the rows.
215 // Least, if we cut in a middle of a row, we add the remaining characters,
216 // which is (8 - (k * 2)).
218 W
.getOStream() << format("%*c", (4 - i
) * 8 + (4 - i
), ' ');
220 W
.getOStream() << format("%*c", 8 - k
* 2, ' ');
223 for (i
= 0; TmpSecPtr
+ i
< SecEnd
&& i
< 16; ++i
)
224 W
.getOStream() << (isPrint(TmpSecPtr
[i
])
225 ? static_cast<char>(TmpSecPtr
[i
])
228 W
.getOStream() << '\n';