Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/llvm/tools/llvm-objdump/XCOFFDump.cpp
35231 views
1
//===-- XCOFFDump.cpp - XCOFF-specific dumper -----------------------------===//
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 the XCOFF-specific dumper for llvm-objdump.
11
///
12
//===----------------------------------------------------------------------===//
13
14
#include "XCOFFDump.h"
15
16
#include "llvm-objdump.h"
17
#include "llvm/ADT/StringExtras.h"
18
#include "llvm/Demangle/Demangle.h"
19
#include "llvm/MC/MCInstPrinter.h"
20
#include "llvm/MC/MCSubtargetInfo.h"
21
#include "llvm/Support/Casting.h"
22
#include "llvm/Support/Endian.h"
23
#include "llvm/Support/FormattedStream.h"
24
#include <algorithm>
25
26
using namespace llvm;
27
using namespace llvm::object;
28
using namespace llvm::XCOFF;
29
using namespace llvm::support;
30
31
namespace {
32
class XCOFFDumper : public objdump::Dumper {
33
public:
34
XCOFFDumper(const object::XCOFFObjectFile &O) : Dumper(O) {}
35
void printPrivateHeaders() override {}
36
};
37
} // namespace
38
39
std::unique_ptr<objdump::Dumper>
40
objdump::createXCOFFDumper(const object::XCOFFObjectFile &Obj) {
41
return std::make_unique<XCOFFDumper>(Obj);
42
}
43
44
Error objdump::getXCOFFRelocationValueString(const XCOFFObjectFile &Obj,
45
const RelocationRef &Rel,
46
bool SymbolDescription,
47
SmallVectorImpl<char> &Result) {
48
symbol_iterator SymI = Rel.getSymbol();
49
if (SymI == Obj.symbol_end())
50
return make_error<GenericBinaryError>(
51
"invalid symbol reference in relocation entry",
52
object_error::parse_failed);
53
54
Expected<StringRef> SymNameOrErr = SymI->getName();
55
if (!SymNameOrErr)
56
return SymNameOrErr.takeError();
57
58
std::string SymName =
59
Demangle ? demangle(*SymNameOrErr) : SymNameOrErr->str();
60
if (SymbolDescription)
61
SymName = getXCOFFSymbolDescription(createSymbolInfo(Obj, *SymI), SymName);
62
63
Result.append(SymName.begin(), SymName.end());
64
return Error::success();
65
}
66
67
std::optional<XCOFF::StorageMappingClass>
68
objdump::getXCOFFSymbolCsectSMC(const XCOFFObjectFile &Obj,
69
const SymbolRef &Sym) {
70
const XCOFFSymbolRef SymRef = Obj.toSymbolRef(Sym.getRawDataRefImpl());
71
72
if (!SymRef.isCsectSymbol())
73
return std::nullopt;
74
75
auto CsectAuxEntOrErr = SymRef.getXCOFFCsectAuxRef();
76
if (!CsectAuxEntOrErr)
77
return std::nullopt;
78
79
return CsectAuxEntOrErr.get().getStorageMappingClass();
80
}
81
82
std::optional<object::SymbolRef>
83
objdump::getXCOFFSymbolContainingSymbolRef(const XCOFFObjectFile &Obj,
84
const SymbolRef &Sym) {
85
const XCOFFSymbolRef SymRef = Obj.toSymbolRef(Sym.getRawDataRefImpl());
86
if (!SymRef.isCsectSymbol())
87
return std::nullopt;
88
89
Expected<XCOFFCsectAuxRef> CsectAuxEntOrErr = SymRef.getXCOFFCsectAuxRef();
90
if (!CsectAuxEntOrErr || !CsectAuxEntOrErr.get().isLabel())
91
return std::nullopt;
92
uint32_t Idx =
93
static_cast<uint32_t>(CsectAuxEntOrErr.get().getSectionOrLength());
94
DataRefImpl DRI;
95
DRI.p = Obj.getSymbolByIndex(Idx);
96
return SymbolRef(DRI, &Obj);
97
}
98
99
bool objdump::isLabel(const XCOFFObjectFile &Obj, const SymbolRef &Sym) {
100
const XCOFFSymbolRef SymRef = Obj.toSymbolRef(Sym.getRawDataRefImpl());
101
if (!SymRef.isCsectSymbol())
102
return false;
103
104
auto CsectAuxEntOrErr = SymRef.getXCOFFCsectAuxRef();
105
if (!CsectAuxEntOrErr)
106
return false;
107
108
return CsectAuxEntOrErr.get().isLabel();
109
}
110
111
std::string objdump::getXCOFFSymbolDescription(const SymbolInfoTy &SymbolInfo,
112
StringRef SymbolName) {
113
assert(SymbolInfo.isXCOFF() && "Must be a XCOFFSymInfo.");
114
115
std::string Result;
116
// Dummy symbols have no symbol index.
117
if (SymbolInfo.XCOFFSymInfo.Index)
118
Result =
119
("(idx: " + Twine(*SymbolInfo.XCOFFSymInfo.Index) + ") " + SymbolName)
120
.str();
121
else
122
Result.append(SymbolName.begin(), SymbolName.end());
123
124
if (SymbolInfo.XCOFFSymInfo.StorageMappingClass &&
125
!SymbolInfo.XCOFFSymInfo.IsLabel) {
126
const XCOFF::StorageMappingClass Smc =
127
*SymbolInfo.XCOFFSymInfo.StorageMappingClass;
128
Result.append(("[" + XCOFF::getMappingClassString(Smc) + "]").str());
129
}
130
131
return Result;
132
}
133
134
#define PRINTBOOL(Prefix, Obj, Field) \
135
OS << Prefix << " " << ((Obj.Field()) ? "+" : "-") << #Field
136
137
#define PRINTGET(Prefix, Obj, Field) \
138
OS << Prefix << " " << #Field << " = " \
139
<< static_cast<unsigned>(Obj.get##Field())
140
141
#define PRINTOPTIONAL(Field) \
142
if (TbTable.get##Field()) { \
143
OS << '\n'; \
144
printRawData(Bytes.slice(Index, 4), Address + Index, OS, STI); \
145
Index += 4; \
146
OS << "\t# " << #Field << " = " << *TbTable.get##Field(); \
147
}
148
149
void objdump::dumpTracebackTable(ArrayRef<uint8_t> Bytes, uint64_t Address,
150
formatted_raw_ostream &OS, uint64_t End,
151
const MCSubtargetInfo &STI,
152
const XCOFFObjectFile *Obj) {
153
uint64_t Index = 0;
154
unsigned TabStop = getInstStartColumn(STI) - 1;
155
// Print traceback table boundary.
156
printRawData(Bytes.slice(Index, 4), Address, OS, STI);
157
OS << "\t# Traceback table start\n";
158
Index += 4;
159
160
uint64_t Size = End - Address;
161
bool Is64Bit = Obj->is64Bit();
162
163
// XCOFFTracebackTable::create modifies the size parameter, so ensure Size
164
// isn't changed.
165
uint64_t SizeCopy = End - Address;
166
Expected<XCOFFTracebackTable> TTOrErr =
167
XCOFFTracebackTable::create(Bytes.data() + Index, SizeCopy, Is64Bit);
168
169
if (!TTOrErr) {
170
std::string WarningMsgStr;
171
raw_string_ostream WarningStream(WarningMsgStr);
172
WarningStream << "failure parsing traceback table with address: 0x"
173
<< utohexstr(Address) + "\n>>> "
174
<< toString(TTOrErr.takeError())
175
<< "\n>>> Raw traceback table data is:\n";
176
177
uint64_t LastNonZero = Index;
178
for (uint64_t I = Index; I < Size; I += 4)
179
if (support::endian::read32be(Bytes.slice(I, 4).data()) != 0)
180
LastNonZero = I + 4 > Size ? Size : I + 4;
181
182
if (Size - LastNonZero <= 4)
183
LastNonZero = Size;
184
185
formatted_raw_ostream FOS(WarningStream);
186
while (Index < LastNonZero) {
187
printRawData(Bytes.slice(Index, 4), Address + Index, FOS, STI);
188
Index += 4;
189
WarningStream << '\n';
190
}
191
192
// Print all remaining zeroes as ...
193
if (Size - LastNonZero >= 8)
194
WarningStream << "\t\t...\n";
195
196
reportWarning(WarningMsgStr, Obj->getFileName());
197
return;
198
}
199
200
auto PrintBytes = [&](uint64_t N) {
201
printRawData(Bytes.slice(Index, N), Address + Index, OS, STI);
202
Index += N;
203
};
204
205
XCOFFTracebackTable TbTable = *TTOrErr;
206
// Print the first of the 8 bytes of mandatory fields.
207
PrintBytes(1);
208
OS << format("\t# Version = %i", TbTable.getVersion()) << '\n';
209
210
// Print the second of the 8 bytes of mandatory fields.
211
PrintBytes(1);
212
TracebackTable::LanguageID LangId =
213
static_cast<TracebackTable::LanguageID>(TbTable.getLanguageID());
214
OS << "\t# Language = " << getNameForTracebackTableLanguageId(LangId) << '\n';
215
216
auto Split = [&]() {
217
OS << '\n';
218
OS.indent(TabStop);
219
};
220
221
// Print the third of the 8 bytes of mandatory fields.
222
PrintBytes(1);
223
PRINTBOOL("\t#", TbTable, isGlobalLinkage);
224
PRINTBOOL(",", TbTable, isOutOfLineEpilogOrPrologue);
225
Split();
226
PRINTBOOL("\t ", TbTable, hasTraceBackTableOffset);
227
PRINTBOOL(",", TbTable, isInternalProcedure);
228
Split();
229
PRINTBOOL("\t ", TbTable, hasControlledStorage);
230
PRINTBOOL(",", TbTable, isTOCless);
231
Split();
232
PRINTBOOL("\t ", TbTable, isFloatingPointPresent);
233
Split();
234
PRINTBOOL("\t ", TbTable, isFloatingPointOperationLogOrAbortEnabled);
235
OS << '\n';
236
237
// Print the 4th of the 8 bytes of mandatory fields.
238
PrintBytes(1);
239
PRINTBOOL("\t#", TbTable, isInterruptHandler);
240
PRINTBOOL(",", TbTable, isFuncNamePresent);
241
PRINTBOOL(",", TbTable, isAllocaUsed);
242
Split();
243
PRINTGET("\t ", TbTable, OnConditionDirective);
244
PRINTBOOL(",", TbTable, isCRSaved);
245
PRINTBOOL(",", TbTable, isLRSaved);
246
OS << '\n';
247
248
// Print the 5th of the 8 bytes of mandatory fields.
249
PrintBytes(1);
250
PRINTBOOL("\t#", TbTable, isBackChainStored);
251
PRINTBOOL(",", TbTable, isFixup);
252
PRINTGET(",", TbTable, NumOfFPRsSaved);
253
OS << '\n';
254
255
// Print the 6th of the 8 bytes of mandatory fields.
256
PrintBytes(1);
257
PRINTBOOL("\t#", TbTable, hasExtensionTable);
258
PRINTBOOL(",", TbTable, hasVectorInfo);
259
PRINTGET(",", TbTable, NumOfGPRsSaved);
260
OS << '\n';
261
262
// Print the 7th of the 8 bytes of mandatory fields.
263
PrintBytes(1);
264
PRINTGET("\t#", TbTable, NumberOfFixedParms);
265
OS << '\n';
266
267
// Print the 8th of the 8 bytes of mandatory fields.
268
PrintBytes(1);
269
PRINTGET("\t#", TbTable, NumberOfFPParms);
270
PRINTBOOL(",", TbTable, hasParmsOnStack);
271
272
PRINTOPTIONAL(ParmsType);
273
PRINTOPTIONAL(TraceBackTableOffset);
274
PRINTOPTIONAL(HandlerMask);
275
PRINTOPTIONAL(NumOfCtlAnchors);
276
277
if (TbTable.getControlledStorageInfoDisp()) {
278
SmallVector<uint32_t, 8> Disp = *TbTable.getControlledStorageInfoDisp();
279
for (unsigned I = 0; I < Disp.size(); ++I) {
280
OS << '\n';
281
PrintBytes(4);
282
OS << "\t" << (I ? " " : "#") << " ControlledStorageInfoDisp[" << I
283
<< "] = " << Disp[I];
284
}
285
}
286
287
// If there is a name, print the function name and function name length.
288
if (TbTable.isFuncNamePresent()) {
289
uint16_t FunctionNameLen = TbTable.getFunctionName()->size();
290
if (FunctionNameLen == 0) {
291
OS << '\n';
292
reportWarning(
293
"the length of the function name must be greater than zero if the "
294
"isFuncNamePresent bit is set in the traceback table",
295
Obj->getFileName());
296
return;
297
}
298
299
OS << '\n';
300
PrintBytes(2);
301
OS << "\t# FunctionNameLen = " << FunctionNameLen;
302
303
uint16_t RemainingBytes = FunctionNameLen;
304
bool HasPrinted = false;
305
while (RemainingBytes > 0) {
306
OS << '\n';
307
uint16_t PrintLen = RemainingBytes >= 4 ? 4 : RemainingBytes;
308
printRawData(Bytes.slice(Index, PrintLen), Address + Index, OS, STI);
309
Index += PrintLen;
310
RemainingBytes -= PrintLen;
311
312
if (!HasPrinted) {
313
OS << "\t# FunctionName = " << *TbTable.getFunctionName();
314
HasPrinted = true;
315
}
316
}
317
}
318
319
if (TbTable.isAllocaUsed()) {
320
OS << '\n';
321
PrintBytes(1);
322
OS << format("\t# AllocaRegister = %u", *TbTable.getAllocaRegister());
323
}
324
325
if (TbTable.getVectorExt()) {
326
OS << '\n';
327
TBVectorExt VecExt = *TbTable.getVectorExt();
328
// Print first byte of VectorExt.
329
PrintBytes(1);
330
PRINTGET("\t#", VecExt, NumberOfVRSaved);
331
PRINTBOOL(",", VecExt, isVRSavedOnStack);
332
PRINTBOOL(",", VecExt, hasVarArgs);
333
OS << '\n';
334
335
// Print the second byte of VectorExt.
336
PrintBytes(1);
337
PRINTGET("\t#", VecExt, NumberOfVectorParms);
338
PRINTBOOL(",", VecExt, hasVMXInstruction);
339
OS << '\n';
340
341
PrintBytes(4);
342
OS << "\t# VectorParmsInfoString = " << VecExt.getVectorParmsInfo();
343
344
// There are two bytes of padding after vector info.
345
OS << '\n';
346
PrintBytes(2);
347
OS << "\t# Padding";
348
}
349
350
if (TbTable.getExtensionTable()) {
351
OS << '\n';
352
PrintBytes(1);
353
ExtendedTBTableFlag Flag =
354
static_cast<ExtendedTBTableFlag>(*TbTable.getExtensionTable());
355
OS << "\t# ExtensionTable = " << getExtendedTBTableFlagString(Flag);
356
}
357
358
if (TbTable.getEhInfoDisp()) {
359
// There are 4 bytes alignment before eh info displacement.
360
if (Index % 4) {
361
OS << '\n';
362
PrintBytes(4 - Index % 4);
363
OS << "\t# Alignment padding for eh info displacement";
364
}
365
OS << '\n';
366
// The size of the displacement (address) is 4 bytes in 32-bit object files,
367
// and 8 bytes in 64-bit object files.
368
PrintBytes(4);
369
OS << "\t# EH info displacement";
370
if (Is64Bit) {
371
OS << '\n';
372
PrintBytes(4);
373
}
374
}
375
376
OS << '\n';
377
if (End == Address + Index)
378
return;
379
380
Size = End - Address;
381
382
const char *LineSuffix = "\t# Padding\n";
383
auto IsWordZero = [&](uint64_t WordPos) {
384
if (WordPos >= Size)
385
return false;
386
uint64_t LineLength = std::min(4 - WordPos % 4, Size - WordPos);
387
return std::all_of(Bytes.begin() + WordPos,
388
Bytes.begin() + WordPos + LineLength,
389
[](uint8_t Byte) { return Byte == 0; });
390
};
391
392
bool AreWordsZero[] = {IsWordZero(Index), IsWordZero(alignTo(Index, 4) + 4),
393
IsWordZero(alignTo(Index, 4) + 8)};
394
bool ShouldPrintLine = true;
395
while (true) {
396
// Determine the length of the line (4, except for the first line, which
397
// will be just enough to align to the word boundary, and the last line,
398
// which will be the remainder of the data).
399
uint64_t LineLength = std::min(4 - Index % 4, Size - Index);
400
if (ShouldPrintLine) {
401
// Print the line.
402
printRawData(Bytes.slice(Index, LineLength), Address + Index, OS, STI);
403
OS << LineSuffix;
404
LineSuffix = "\n";
405
}
406
407
Index += LineLength;
408
if (Index == Size)
409
return;
410
411
// For 3 or more consecutive lines of zeros, skip all but the first one, and
412
// replace them with "...".
413
if (AreWordsZero[0] && AreWordsZero[1] && AreWordsZero[2]) {
414
if (ShouldPrintLine)
415
OS << std::string(8, ' ') << "...\n";
416
ShouldPrintLine = false;
417
} else if (!AreWordsZero[1]) {
418
// We have reached the end of a skipped block of zeros.
419
ShouldPrintLine = true;
420
}
421
AreWordsZero[0] = AreWordsZero[1];
422
AreWordsZero[1] = AreWordsZero[2];
423
AreWordsZero[2] = IsWordZero(Index + 8);
424
}
425
}
426
#undef PRINTBOOL
427
#undef PRINTGET
428
#undef PRINTOPTIONAL
429
430