Skip to content

Commit

Permalink
[llvm-objdump] Print out xcoff file header for xcoff object file with…
Browse files Browse the repository at this point in the history
… option private-headers (#96350)

Print out the XCOFF file header and load section header for the XCOFF
object file using llvm-objdump with the --private-headers option.
  • Loading branch information
diggerlin authored Aug 15, 2024
1 parent 7332713 commit 29b0a25
Show file tree
Hide file tree
Showing 2 changed files with 132 additions and 2 deletions.
52 changes: 52 additions & 0 deletions llvm/test/tools/llvm-objdump/XCOFF/private-headers.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
## Test the --private-headers option for XCOFF object files.

# RUN: yaml2obj -DMAGIC=0x1DF --docnum=1 %s -o %t_xcoff32.o
# RUN: yaml2obj -DMAGIC=0x1F7 --docnum=1 %s -o %t_xcoff64.o
# RUN: llvm-objdump --private-headers %t_xcoff32.o | \
# RUN: FileCheck %s --check-prefixes=CHECK32 --match-full-lines --strict-whitespace
# RUN: llvm-objdump --private-headers %t_xcoff64.o | \
# RUN: FileCheck %s --check-prefixes=CHECK64 --match-full-lines --strict-whitespace

--- !XCOFF
FileHeader:
MagicNumber: [[MAGIC]]
CreationTime: 1234
Sections:
- Name: .text
Flags: [ STYP_TEXT ]
SectionData: "9061FFF880820000"
- Name: .data
Flags: [ STYP_DATA ]
SectionData: "0000000000000FC0"

# CHECK32:---File Header:
# CHECK32-NEXT:Magic: 0x1df
# CHECK32-NEXT:NumberOfSections: 2
# CHECK32-NEXT:Timestamp: 1970-01-01 00:20:34 (1234)
# CHECK32-NEXT:SymbolTableOffset: 0x0
# CHECK32-NEXT:SymbolTableEntries: 0
# CHECK32-NEXT:OptionalHeaderSize: 0x0
# CHECK32-NEXT:Flags: 0x0

# CHECK64:---File Header:
# CHECK64-NEXT:Magic: 0x1f7
# CHECK64-NEXT:NumberOfSections: 2
# CHECK64-NEXT:Timestamp: 1970-01-01 00:20:34 (1234)
# CHECK64-NEXT:SymbolTableOffset: 0x0
# CHECK64-NEXT:SymbolTableEntries: 0
# CHECK64-NEXT:OptionalHeaderSize: 0x0
# CHECK64-NEXT:Flags: 0x0

## Test if the creation time of XCOFF is zero and the number of symbols is negative.
# RUN: yaml2obj -DMAGIC=0x1DF --docnum=2 %s -o %t_xcoff_timestamp.o
# RUN: llvm-objdump --private-headers %t_xcoff_timestamp.o | \
# RUN: FileCheck %s --match-full-lines

--- !XCOFF
FileHeader:
MagicNumber: 0x1DF
CreationTime: 0
EntriesInSymbolTable: -1

# CHECK: Timestamp: None (0)
# CHECK: SymbolTableEntries: Reserved Value (-1)
82 changes: 80 additions & 2 deletions llvm/tools/llvm-objdump/XCOFFDump.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/FormattedStream.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>

using namespace llvm;
Expand All @@ -30,10 +32,86 @@ using namespace llvm::support;

namespace {
class XCOFFDumper : public objdump::Dumper {
const XCOFFObjectFile &Obj;
unsigned Width;

public:
XCOFFDumper(const object::XCOFFObjectFile &O) : Dumper(O) {}
void printPrivateHeaders() override {}
XCOFFDumper(const object::XCOFFObjectFile &O) : Dumper(O), Obj(O) {}

private:
void printPrivateHeaders() override;
void printFileHeader();
FormattedString formatName(StringRef Name);
void printHex(StringRef Name, uint64_t Value);
void printNumber(StringRef Name, uint64_t Value);
void printStrHex(StringRef Name, StringRef Str, uint64_t Value);
void setWidth(unsigned W) { Width = W; };
};

void XCOFFDumper::printPrivateHeaders() { printFileHeader(); }

FormattedString XCOFFDumper::formatName(StringRef Name) {
return FormattedString(Name, Width, FormattedString::JustifyLeft);
}

void XCOFFDumper::printHex(StringRef Name, uint64_t Value) {
outs() << formatName(Name) << format_hex(Value, 0) << "\n";
}

void XCOFFDumper::printNumber(StringRef Name, uint64_t Value) {
outs() << formatName(Name) << format_decimal(Value, 0) << "\n";
}

void XCOFFDumper::printStrHex(StringRef Name, StringRef Str, uint64_t Value) {
outs() << formatName(Name) << Str << " (" << format_decimal(Value, 0)
<< ")\n";
}

void XCOFFDumper::printFileHeader() {
setWidth(20);
outs() << "\n---File Header:\n";
printHex("Magic:", Obj.getMagic());
printNumber("NumberOfSections:", Obj.getNumberOfSections());

int32_t Timestamp = Obj.getTimeStamp();
if (Timestamp > 0) {
// This handling of the timestamp assumes that the host system's time_t is
// compatible with AIX time_t. If a platform is not compatible, the lit
// tests will let us know.
time_t TimeDate = Timestamp;

char FormattedTime[20] = {};

size_t BytesFormatted = std::strftime(FormattedTime, sizeof(FormattedTime),
"%F %T", std::gmtime(&TimeDate));
assert(BytesFormatted && "The size of the buffer FormattedTime is less "
"than the size of the date/time string.");
printStrHex("Timestamp:", FormattedTime, Timestamp);
} else {
// Negative timestamp values are reserved for future use.
printStrHex("Timestamp:", Timestamp == 0 ? "None" : "Reserved Value",
Timestamp);
}

// The number of symbol table entries is an unsigned value in 64-bit objects
// and a signed value (with negative values being 'reserved') in 32-bit
// objects.
if (Obj.is64Bit()) {
printHex("SymbolTableOffset:", Obj.getSymbolTableOffset64());
printNumber("SymbolTableEntries:", Obj.getNumberOfSymbolTableEntries64());
} else {
printHex("SymbolTableOffset:", Obj.getSymbolTableOffset32());
int32_t SymTabEntries = Obj.getRawNumberOfSymbolTableEntries32();
if (SymTabEntries >= 0)
printNumber("SymbolTableEntries:", SymTabEntries);
else
printStrHex("SymbolTableEntries:", "Reserved Value", SymTabEntries);
}

printHex("OptionalHeaderSize:", Obj.getOptionalHeaderSize());
printHex("Flags:", Obj.getFlags());
}

} // namespace

std::unique_ptr<objdump::Dumper>
Expand Down

0 comments on commit 29b0a25

Please sign in to comment.