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/ObjectFile.h"
18 #include "llvm/Support/Error.h"
19 #include "llvm/Support/FormatVariadic.h"
20 #include "llvm/Support/ScopedPrinter.h"
21 #include "llvm/Support/raw_ostream.h"
26 static inline Error
createError(const Twine
&Msg
) {
27 return createStringError(object::object_error::parse_failed
, Msg
);
30 ObjDumper::ObjDumper(ScopedPrinter
&Writer
, StringRef ObjName
) : W(Writer
) {
31 // Dumper reports all non-critical errors as warnings.
32 // It does not print the same warning more than once.
33 WarningHandler
= [=](const Twine
&Msg
) {
34 if (Warnings
.insert(Msg
.str()).second
)
35 reportWarning(createError(Msg
), ObjName
);
36 return Error::success();
40 ObjDumper::~ObjDumper() {}
42 void ObjDumper::reportUniqueWarning(Error Err
) const {
43 reportUniqueWarning(toString(std::move(Err
)));
46 void ObjDumper::reportUniqueWarning(const Twine
&Msg
) const {
47 cantFail(WarningHandler(Msg
),
48 "WarningHandler should always return ErrorSuccess");
51 static void printAsPrintable(raw_ostream
&W
, const uint8_t *Start
, size_t Len
) {
52 for (size_t i
= 0; i
< Len
; i
++)
53 W
<< (isPrint(Start
[i
]) ? static_cast<char>(Start
[i
]) : '.');
56 void ObjDumper::printAsStringList(StringRef StringContent
,
57 size_t StringDataOffset
) {
58 size_t StrSize
= StringContent
.size();
61 if (StrSize
< StringDataOffset
) {
62 reportUniqueWarning("offset (0x" + Twine::utohexstr(StringDataOffset
) +
63 ") is past the end of the contents (size 0x" +
64 Twine::utohexstr(StrSize
) + ")");
68 const uint8_t *StrContent
= StringContent
.bytes_begin();
69 // Some formats contain additional metadata at the start which should not be
70 // interpreted as strings. Skip these bytes, but account for them in the
72 const uint8_t *CurrentWord
= StrContent
+ StringDataOffset
;
73 const uint8_t *StrEnd
= StringContent
.bytes_end();
75 while (CurrentWord
<= StrEnd
) {
76 size_t WordSize
= strnlen(reinterpret_cast<const char *>(CurrentWord
),
77 StrEnd
- CurrentWord
);
82 W
.startLine() << format("[%6tx] ", CurrentWord
- StrContent
);
83 printAsPrintable(W
.startLine(), CurrentWord
, WordSize
);
84 W
.startLine() << '\n';
85 CurrentWord
+= WordSize
+ 1;
89 void ObjDumper::printFileSummary(StringRef FileStr
, object::ObjectFile
&Obj
,
90 ArrayRef
<std::string
> InputFilenames
,
91 const object::Archive
*A
) {
92 W
.startLine() << "\n";
93 W
.printString("File", FileStr
);
94 W
.printString("Format", Obj
.getFileFormatName());
95 W
.printString("Arch", Triple::getArchTypeName(Obj
.getArch()));
96 W
.printString("AddressSize",
97 std::string(formatv("{0}bit", 8 * Obj
.getBytesInAddress())));
98 this->printLoadName();
101 static std::vector
<object::SectionRef
>
102 getSectionRefsByNameOrIndex(const object::ObjectFile
&Obj
,
103 ArrayRef
<std::string
> Sections
) {
104 std::vector
<object::SectionRef
> Ret
;
105 std::map
<std::string
, bool> SecNames
;
106 std::map
<unsigned, bool> SecIndices
;
108 for (StringRef Section
: Sections
) {
109 if (!Section
.getAsInteger(0, SecIndex
))
110 SecIndices
.emplace(SecIndex
, false);
112 SecNames
.emplace(std::string(Section
), false);
115 SecIndex
= Obj
.isELF() ? 0 : 1;
116 for (object::SectionRef SecRef
: Obj
.sections()) {
117 StringRef SecName
= unwrapOrError(Obj
.getFileName(), SecRef
.getName());
118 auto NameIt
= SecNames
.find(std::string(SecName
));
119 if (NameIt
!= SecNames
.end())
120 NameIt
->second
= true;
121 auto IndexIt
= SecIndices
.find(SecIndex
);
122 if (IndexIt
!= SecIndices
.end())
123 IndexIt
->second
= true;
124 if (NameIt
!= SecNames
.end() || IndexIt
!= SecIndices
.end())
125 Ret
.push_back(SecRef
);
129 for (const std::pair
<const std::string
, bool> &S
: SecNames
)
132 createError(formatv("could not find section '{0}'", S
.first
).str()),
135 for (std::pair
<unsigned, bool> S
: SecIndices
)
138 createError(formatv("could not find section {0}", S
.first
).str()),
144 void ObjDumper::printSectionsAsString(const object::ObjectFile
&Obj
,
145 ArrayRef
<std::string
> Sections
) {
147 for (object::SectionRef Section
:
148 getSectionRefsByNameOrIndex(Obj
, Sections
)) {
149 StringRef SectionName
= unwrapOrError(Obj
.getFileName(), Section
.getName());
152 W
.startLine() << '\n';
154 W
.startLine() << "String dump of section '" << SectionName
<< "':\n";
156 StringRef SectionContent
=
157 unwrapOrError(Obj
.getFileName(), Section
.getContents());
158 printAsStringList(SectionContent
);
162 void ObjDumper::printSectionsAsHex(const object::ObjectFile
&Obj
,
163 ArrayRef
<std::string
> Sections
) {
165 for (object::SectionRef Section
:
166 getSectionRefsByNameOrIndex(Obj
, Sections
)) {
167 StringRef SectionName
= unwrapOrError(Obj
.getFileName(), Section
.getName());
170 W
.startLine() << '\n';
172 W
.startLine() << "Hex dump of section '" << SectionName
<< "':\n";
174 StringRef SectionContent
=
175 unwrapOrError(Obj
.getFileName(), Section
.getContents());
176 const uint8_t *SecContent
= SectionContent
.bytes_begin();
177 const uint8_t *SecEnd
= SecContent
+ SectionContent
.size();
179 for (const uint8_t *SecPtr
= SecContent
; SecPtr
< SecEnd
; SecPtr
+= 16) {
180 const uint8_t *TmpSecPtr
= SecPtr
;
184 W
.startLine() << format_hex(Section
.getAddress() + (SecPtr
- SecContent
),
186 W
.startLine() << ' ';
187 for (i
= 0; TmpSecPtr
< SecEnd
&& i
< 4; ++i
) {
188 for (k
= 0; TmpSecPtr
< SecEnd
&& k
< 4; k
++, TmpSecPtr
++) {
189 uint8_t Val
= *(reinterpret_cast<const uint8_t *>(TmpSecPtr
));
190 W
.startLine() << format_hex_no_prefix(Val
, 2);
192 W
.startLine() << ' ';
195 // We need to print the correct amount of spaces to match the format.
196 // We are adding the (4 - i) last rows that are 8 characters each.
197 // Then, the (4 - i) spaces that are in between the rows.
198 // Least, if we cut in a middle of a row, we add the remaining characters,
199 // which is (8 - (k * 2)).
201 W
.startLine() << format("%*c", (4 - i
) * 8 + (4 - i
), ' ');
203 W
.startLine() << format("%*c", 8 - k
* 2, ' ');
206 for (i
= 0; TmpSecPtr
+ i
< SecEnd
&& i
< 16; ++i
)
207 W
.startLine() << (isPrint(TmpSecPtr
[i
])
208 ? static_cast<char>(TmpSecPtr
[i
])
211 W
.startLine() << '\n';