Skip to content

Commit

Permalink
[dsymutil] Implement -symtab/-s option.
Browse files Browse the repository at this point in the history
This option dumps the STAB entries that define the debug map(s)
stored in the input binaries, and then exits.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@246403 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
fredriss committed Aug 31, 2015
1 parent ae55d35 commit a8a34c5
Show file tree
Hide file tree
Showing 4 changed files with 237 additions and 0 deletions.
44 changes: 44 additions & 0 deletions test/tools/dsymutil/dump-symtab.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
RUN: llvm-dsymutil -s %p/Inputs/fat-test.dylib | FileCheck -check-prefix=ALL -check-prefix=I386 %s
RUN: llvm-dsymutil -arch i386 -s %p/Inputs/fat-test.dylib | FileCheck -check-prefix=I386 -check-prefix=ONE %s


ALL: ----------------------------------------------------------------------
ALL-NEXT: Symbol table for: '{{.*}}fat-test.dylib' (x86_64)
ALL-NEXT: ----------------------------------------------------------------------
ALL-NEXT: Index n_strx n_type n_sect n_desc n_value
ALL-NEXT: ======== -------- ------------------ ------ ------ ----------------
ALL-NEXT: [ 0] 00000002 64 (N_SO ) 00 0000 0000000000000000 '/Inputs/'
ALL-NEXT: [ 1] 0000000b 64 (N_SO ) 00 0000 0000000000000000 'fat-test.c'
ALL-NEXT: [ 2] 00000016 66 (N_OSO ) 03 0001 0000000055b1d0b9 '/Inputs/fat-test.o'
ALL-NEXT: [ 3] 00000029 20 (N_GSYM ) 00 0000 0000000000000000 '_x86_64_var'
ALL-NEXT: [ 4] 00000001 64 (N_SO ) 01 0000 0000000000000000
ALL-NEXT: [ 5] 00000035 0f ( SECT EXT) 02 0000 0000000000001000 '_x86_64_var'
ALL-NEXT: [ 6] 00000041 01 ( UNDF EXT) 00 0100 0000000000000000 'dyld_stub_binder'

I386: ----------------------------------------------------------------------
I386-NEXT: Symbol table for: '{{.*}}fat-test.dylib' (i386)
I386-NEXT: ----------------------------------------------------------------------
I386-NEXT: Index n_strx n_type n_sect n_desc n_value
I386-NEXT: ======== -------- ------------------ ------ ------ ----------------
I386-NEXT: [ 0] 00000002 64 (N_SO ) 00 0000 0000000000000000 '/Inputs/'
I386-NEXT: [ 1] 0000000b 64 (N_SO ) 00 0000 0000000000000000 'fat-test.c'
I386-NEXT: [ 2] 00000016 66 (N_OSO ) 03 0001 0000000055b1d0b9 '/Inputs/fat-test.o'
I386-NEXT: [ 3] 00000029 20 (N_GSYM ) 00 0000 0000000000000000 '_i386_var'
I386-NEXT: [ 4] 00000001 64 (N_SO ) 01 0000 0000000000000000
I386-NEXT: [ 5] 00000033 0f ( SECT EXT) 02 0000 0000000000001000 '_i386_var'
I386-NEXT: [ 6] 0000003d 01 ( UNDF EXT) 00 0100 0000000000000000 'dyld_stub_binder'

ONE-NOT: Symbol table

ALL: ----------------------------------------------------------------------
ALL-NEXT: Symbol table for: '{{.*}}fat-test.dylib' (x86_64h)
ALL-NEXT: ----------------------------------------------------------------------
ALL-NEXT: Index n_strx n_type n_sect n_desc n_value
ALL-NEXT: ======== -------- ------------------ ------ ------ ----------------
ALL-NEXT: [ 0] 00000002 64 (N_SO ) 00 0000 0000000000000000 '/Inputs/'
ALL-NEXT: [ 1] 0000000b 64 (N_SO ) 00 0000 0000000000000000 'fat-test.c'
ALL-NEXT: [ 2] 00000016 66 (N_OSO ) 08 0001 0000000055b1d0b9 '/Inputs/fat-test.o'
ALL-NEXT: [ 3] 00000029 20 (N_GSYM ) 00 0000 0000000000000000 '_x86_64h_var'
ALL-NEXT: [ 4] 00000001 64 (N_SO ) 01 0000 0000000000000000
ALL-NEXT: [ 5] 00000036 0f ( SECT EXT) 02 0000 0000000000001000 '_x86_64h_var'
ALL-NEXT: [ 6] 00000043 01 ( UNDF EXT) 00 0100 0000000000000000 'dyld_stub_binder'
175 changes: 175 additions & 0 deletions tools/dsymutil/MachODebugMapParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ class MachODebugMapParser {
/// or isn't of a supported type.
ErrorOr<std::vector<std::unique_ptr<DebugMap>>> parse();

/// Walk the symbol table and dump it.
bool dumpStab();

private:
std::string BinaryPath;
SmallVector<StringRef, 1> Archs;
Expand Down Expand Up @@ -74,6 +77,22 @@ class MachODebugMapParser {
handleStabSymbolTableEntry(STE.n_strx, STE.n_type, STE.n_sect, STE.n_desc,
STE.n_value);
}

/// Dump the symbol table output header.
void dumpSymTabHeader(raw_ostream &OS, StringRef Arch);

/// Dump the contents of nlist entries.
void dumpSymTabEntry(raw_ostream &OS, uint64_t Index, uint32_t StringIndex,
uint8_t Type, uint8_t SectionIndex, uint16_t Flags,
uint64_t Value);

template <typename STEType>
void dumpSymTabEntry(raw_ostream &OS, uint64_t Index, const STEType &STE) {
dumpSymTabEntry(OS, Index, STE.n_strx, STE.n_type, STE.n_sect, STE.n_desc,
STE.n_value);
}
void dumpOneBinaryStab(const MachOObjectFile &MainBinary,
StringRef BinaryPath);
};

static void Warning(const Twine &Msg) { errs() << "warning: " + Msg + "\n"; }
Expand Down Expand Up @@ -116,6 +135,12 @@ void MachODebugMapParser::switchToNewDebugMapObject(StringRef Filename,
loadCurrentObjectFileSymbols(*ErrOrAchObj);
}

static std::string getArchName(const object::MachOObjectFile &Obj) {
Triple ThumbTriple;
Triple T = Obj.getArch(nullptr, &ThumbTriple);
return T.getArchName();
}

std::unique_ptr<DebugMap>
MachODebugMapParser::parseOneBinary(const MachOObjectFile &MainBinary,
StringRef BinaryPath) {
Expand All @@ -135,6 +160,133 @@ MachODebugMapParser::parseOneBinary(const MachOObjectFile &MainBinary,
return std::move(Result);
}

// Table that maps Darwin's Mach-O stab constants to strings to allow printing.
// llvm-nm has very similar code, the strings used here are however slightly
// different and part of the interface of dsymutil (some project's build-systems
// parse the ouptut of dsymutil -s), thus they shouldn't be changed.
struct DarwinStabName {
uint8_t NType;
const char *Name;
};

static const struct DarwinStabName DarwinStabNames[] = {
{MachO::N_GSYM, "N_GSYM"}, {MachO::N_FNAME, "N_FNAME"},
{MachO::N_FUN, "N_FUN"}, {MachO::N_STSYM, "N_STSYM"},
{MachO::N_LCSYM, "N_LCSYM"}, {MachO::N_BNSYM, "N_BNSYM"},
{MachO::N_PC, "N_PC"}, {MachO::N_AST, "N_AST"},
{MachO::N_OPT, "N_OPT"}, {MachO::N_RSYM, "N_RSYM"},
{MachO::N_SLINE, "N_SLINE"}, {MachO::N_ENSYM, "N_ENSYM"},
{MachO::N_SSYM, "N_SSYM"}, {MachO::N_SO, "N_SO"},
{MachO::N_OSO, "N_OSO"}, {MachO::N_LSYM, "N_LSYM"},
{MachO::N_BINCL, "N_BINCL"}, {MachO::N_SOL, "N_SOL"},
{MachO::N_PARAMS, "N_PARAM"}, {MachO::N_VERSION, "N_VERS"},
{MachO::N_OLEVEL, "N_OLEV"}, {MachO::N_PSYM, "N_PSYM"},
{MachO::N_EINCL, "N_EINCL"}, {MachO::N_ENTRY, "N_ENTRY"},
{MachO::N_LBRAC, "N_LBRAC"}, {MachO::N_EXCL, "N_EXCL"},
{MachO::N_RBRAC, "N_RBRAC"}, {MachO::N_BCOMM, "N_BCOMM"},
{MachO::N_ECOMM, "N_ECOMM"}, {MachO::N_ECOML, "N_ECOML"},
{MachO::N_LENG, "N_LENG"}, {0, 0}};

static const char *getDarwinStabString(uint8_t NType) {
for (unsigned i = 0; DarwinStabNames[i].Name; i++) {
if (DarwinStabNames[i].NType == NType)
return DarwinStabNames[i].Name;
}
return 0;
}

void MachODebugMapParser::dumpSymTabHeader(raw_ostream &OS, StringRef Arch) {
OS << "-----------------------------------"
"-----------------------------------\n";
OS << "Symbol table for: '" << BinaryPath << "' (" << Arch.data() << ")\n";
OS << "-----------------------------------"
"-----------------------------------\n";
OS << "Index n_strx n_type n_sect n_desc n_value\n";
OS << "======== -------- ------------------ ------ ------ ----------------\n";
}

void MachODebugMapParser::dumpSymTabEntry(raw_ostream &OS, uint64_t Index,
uint32_t StringIndex, uint8_t Type,
uint8_t SectionIndex, uint16_t Flags,
uint64_t Value) {

// Index
OS << '[' << format_decimal(Index, 6) << "] "
// n_strx
<< format_hex_no_prefix(StringIndex, 8) << ' '
// n_type...
<< format_hex_no_prefix(Type, 2) << " (";

if (Type & MachO::N_STAB)
OS << left_justify(getDarwinStabString(Type), 13);
else {
if (Type & MachO::N_PEXT)
OS << "PEXT ";
else
OS << " ";
switch (Type & MachO::N_TYPE) {
case MachO::N_UNDF: // 0x0 undefined, n_sect == NO_SECT
OS << "UNDF";
break;
case MachO::N_ABS: // 0x2 absolute, n_sect == NO_SECT
OS << "ABS ";
break;
case MachO::N_SECT: // 0xe defined in section number n_sect
OS << "SECT";
break;
case MachO::N_PBUD: // 0xc prebound undefined (defined in a dylib)
OS << "PBUD";
break;
case MachO::N_INDR: // 0xa indirect
OS << "INDR";
break;
default:
OS << format_hex_no_prefix(Type, 2) << " ";
break;
}
if (Type & MachO::N_EXT)
OS << " EXT";
else
OS << " ";
}

OS << ") "
// n_sect
<< format_hex_no_prefix(SectionIndex, 2) << " "
// n_desc
<< format_hex_no_prefix(Flags, 4) << " "
// n_value
<< format_hex_no_prefix(Value, 16);

const char *Name = &MainBinaryStrings.data()[StringIndex];
if (Name && Name[0])
OS << " '" << Name << "'";

OS << "\n";
}

void MachODebugMapParser::dumpOneBinaryStab(const MachOObjectFile &MainBinary,
StringRef BinaryPath) {
loadMainBinarySymbols(MainBinary);
MainBinaryStrings = MainBinary.getStringTableData();
raw_ostream &OS(llvm::outs());

StringRef ArchName = getArchName(MainBinary);
dumpSymTabHeader(OS, ArchName);
uint64_t Idx = 0;
for (const SymbolRef &Symbol : MainBinary.symbols()) {
const DataRefImpl &DRI = Symbol.getRawDataRefImpl();
if (MainBinary.is64Bit())
dumpSymTabEntry(OS, Idx, MainBinary.getSymbol64TableEntry(DRI));
else
dumpSymTabEntry(OS, Idx, MainBinary.getSymbolTableEntry(DRI));
Idx++;
}

OS << "\n\n";
resetParserState();
}

static bool shouldLinkArch(SmallVectorImpl<StringRef> &Archs, StringRef Arch) {
if (Archs.empty() ||
std::find(Archs.begin(), Archs.end(), "all") != Archs.end() ||
Expand All @@ -148,6 +300,23 @@ static bool shouldLinkArch(SmallVectorImpl<StringRef> &Archs, StringRef Arch) {
return std::find(Archs.begin(), Archs.end(), Arch) != Archs.end();
}

bool MachODebugMapParser::dumpStab() {
auto MainBinOrError =
MainBinaryHolder.GetFilesAs<MachOObjectFile>(BinaryPath);
if (auto Error = MainBinOrError.getError()) {
llvm::errs() << "Cannot get '" << BinaryPath
<< "' as MachO file: " << Error.message() << "\n";
return false;
}

Triple T;
for (const auto *Binary : *MainBinOrError)
if (shouldLinkArch(Archs, Binary->getArch(nullptr, &T).getArchName()))
dumpOneBinaryStab(*Binary, BinaryPath);

return true;
}

/// This main parsing routine tries to open the main binary and if
/// successful iterates over the STAB entries. The real parsing is
/// done in handleStabSymbolTableEntry.
Expand Down Expand Up @@ -297,5 +466,11 @@ parseDebugMap(StringRef InputFile, ArrayRef<std::string> Archs,
return DebugMap::parseYAMLDebugMap(InputFile, PrependPath, Verbose);
}
}

bool dumpStab(StringRef InputFile, ArrayRef<std::string> Archs,
StringRef PrependPath) {
MachODebugMapParser Parser(InputFile, Archs, PrependPath, false);
return Parser.dumpStab();
}
}
}
14 changes: 14 additions & 0 deletions tools/dsymutil/dsymutil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,13 @@ static opt<std::string> OsoPrependPath(
desc("Specify a directory to prepend to the paths of object files."),
value_desc("path"), cat(DsymCategory));

static opt<bool> DumpStab(
"symtab",
desc("Dumps the symbol table found in executable or object file(s) and\n"
"exits."),
init(false), cat(DsymCategory));
static alias DumpStabA("s", desc("Alias for --symtab"), aliasopt(DumpStab));

static opt<bool> FlatOut("flat",
desc("Produce a flat dSYM file (not a bundle)."),
init(false), cat(DsymCategory));
Expand Down Expand Up @@ -274,6 +281,13 @@ int main(int argc, char **argv) {
}

for (auto &InputFile : InputFiles) {
// Dump the symbol table for each input file and requested arch
if (DumpStab) {
if (!dumpStab(InputFile, ArchFlags, OsoPrependPath))
exitDsymutil(1);
continue;
}

auto DebugMapPtrsOrErr = parseDebugMap(InputFile, ArchFlags, OsoPrependPath,
Verbose, InputIsYAMLDebugMap);

Expand Down
4 changes: 4 additions & 0 deletions tools/dsymutil/dsymutil.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ llvm::ErrorOr<std::vector<std::unique_ptr<DebugMap>>>
parseDebugMap(StringRef InputFile, ArrayRef<std::string> Archs,
StringRef PrependPath, bool Verbose, bool InputIsYAML);

/// \brief Dump the symbol table
bool dumpStab(StringRef InputFile, ArrayRef<std::string> Archs,
StringRef PrependPath = "");

/// \brief Link the Dwarf debuginfo as directed by the passed DebugMap
/// \p DM into a DwarfFile named \p OutputFilename.
/// \returns false if the link failed.
Expand Down

0 comments on commit a8a34c5

Please sign in to comment.