mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-22 18:54:02 +01:00
[llvm-nm] - Move MachO specific logic out from the dumpSymbolNamesFromObject(). NFC.
`dumpSymbolNamesFromObject` is the method that dumps symbol names. It has 563 lines, mostly because of huge piece of MachO specific code. In this patch I move it to separate helper method. The new size of `dumpSymbolNamesFromObject` is 93 lines. With it it becomes much easier to maintain it. I had to change the type of 2 name fields to `std::string`, because MachO logic uses temporarily buffer strings (e.g `ExportsNameBuffer`, `BindsNameBuffer` etc): ``` std::string ExportsNameBuffer; raw_string_ostream EOS(ExportsNameBuffer); ``` these buffers were moved to `dumpSymbolsFromDLInfoMachO` by this patch and invalidated after return. Technically, before this patch we had a situation when local pointers (symbol names) were assigned to members of global static `SymbolList`, what is dirty by itself. Differential revision: https://reviews.llvm.org/D94667
This commit is contained in:
parent
5ffb093588
commit
0906a7aca7
@ -295,7 +295,7 @@ struct NMSymbol {
|
||||
uint64_t Address;
|
||||
uint64_t Size;
|
||||
char TypeChar;
|
||||
StringRef Name;
|
||||
std::string Name;
|
||||
StringRef SectionName;
|
||||
StringRef TypeName;
|
||||
BasicSymbolRef Sym;
|
||||
@ -309,7 +309,7 @@ struct NMSymbol {
|
||||
uint8_t NType;
|
||||
uint8_t NSect;
|
||||
uint16_t NDesc;
|
||||
StringRef IndirectName;
|
||||
std::string IndirectName;
|
||||
};
|
||||
} // anonymous namespace
|
||||
|
||||
@ -815,7 +815,7 @@ static void sortAndPrintSymbolList(SymbolicFile &Obj, bool printName,
|
||||
|
||||
for (const NMSymbol &S : SymbolList) {
|
||||
uint32_t SymFlags;
|
||||
std::string Name = S.Name.str();
|
||||
std::string Name = S.Name;
|
||||
MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(&Obj);
|
||||
if (Demangle) {
|
||||
if (Optional<std::string> Opt = demangle(S.Name, MachO))
|
||||
@ -1219,6 +1219,473 @@ static unsigned getNsectInMachO(MachOObjectFile &Obj, BasicSymbolRef Sym) {
|
||||
return (STE.n_type & MachO::N_TYPE) == MachO::N_SECT ? STE.n_sect : 0;
|
||||
}
|
||||
|
||||
static void dumpSymbolsFromDLInfoMachO(MachOObjectFile &MachO) {
|
||||
size_t I = SymbolList.size();
|
||||
std::string ExportsNameBuffer;
|
||||
raw_string_ostream EOS(ExportsNameBuffer);
|
||||
std::string BindsNameBuffer;
|
||||
raw_string_ostream BOS(BindsNameBuffer);
|
||||
std::string LazysNameBuffer;
|
||||
raw_string_ostream LOS(LazysNameBuffer);
|
||||
std::string WeaksNameBuffer;
|
||||
raw_string_ostream WOS(WeaksNameBuffer);
|
||||
std::string FunctionStartsNameBuffer;
|
||||
raw_string_ostream FOS(FunctionStartsNameBuffer);
|
||||
|
||||
MachO::mach_header H;
|
||||
MachO::mach_header_64 H_64;
|
||||
uint32_t HFlags = 0;
|
||||
if (MachO.is64Bit()) {
|
||||
H_64 = MachO.MachOObjectFile::getHeader64();
|
||||
HFlags = H_64.flags;
|
||||
} else {
|
||||
H = MachO.MachOObjectFile::getHeader();
|
||||
HFlags = H.flags;
|
||||
}
|
||||
uint64_t BaseSegmentAddress = 0;
|
||||
for (const auto &Command : MachO.load_commands()) {
|
||||
if (Command.C.cmd == MachO::LC_SEGMENT) {
|
||||
MachO::segment_command Seg = MachO.getSegmentLoadCommand(Command);
|
||||
if (Seg.fileoff == 0 && Seg.filesize != 0) {
|
||||
BaseSegmentAddress = Seg.vmaddr;
|
||||
break;
|
||||
}
|
||||
} else if (Command.C.cmd == MachO::LC_SEGMENT_64) {
|
||||
MachO::segment_command_64 Seg = MachO.getSegment64LoadCommand(Command);
|
||||
if (Seg.fileoff == 0 && Seg.filesize != 0) {
|
||||
BaseSegmentAddress = Seg.vmaddr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (DyldInfoOnly || AddDyldInfo ||
|
||||
HFlags & MachO::MH_NLIST_OUTOFSYNC_WITH_DYLDINFO) {
|
||||
unsigned ExportsAdded = 0;
|
||||
Error Err = Error::success();
|
||||
for (const llvm::object::ExportEntry &Entry : MachO.exports(Err)) {
|
||||
bool found = false;
|
||||
bool ReExport = false;
|
||||
if (!DyldInfoOnly) {
|
||||
for (const NMSymbol &S : SymbolList)
|
||||
if (S.Address == Entry.address() + BaseSegmentAddress &&
|
||||
S.Name == Entry.name()) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
NMSymbol S = {};
|
||||
S.Address = Entry.address() + BaseSegmentAddress;
|
||||
S.Size = 0;
|
||||
S.TypeChar = '\0';
|
||||
S.Name = Entry.name().str();
|
||||
// There is no symbol in the nlist symbol table for this so we set
|
||||
// Sym effectivly to null and the rest of code in here must test for
|
||||
// it and not do things like Sym.getFlags() for it.
|
||||
S.Sym = BasicSymbolRef();
|
||||
S.SymFlags = SymbolRef::SF_Global;
|
||||
S.Section = SectionRef();
|
||||
S.NType = 0;
|
||||
S.NSect = 0;
|
||||
S.NDesc = 0;
|
||||
|
||||
uint64_t EFlags = Entry.flags();
|
||||
bool Abs = ((EFlags & MachO::EXPORT_SYMBOL_FLAGS_KIND_MASK) ==
|
||||
MachO::EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE);
|
||||
bool Resolver = (EFlags & MachO::EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER);
|
||||
ReExport = (EFlags & MachO::EXPORT_SYMBOL_FLAGS_REEXPORT);
|
||||
bool WeakDef = (EFlags & MachO::EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION);
|
||||
if (WeakDef)
|
||||
S.NDesc |= MachO::N_WEAK_DEF;
|
||||
if (Abs) {
|
||||
S.NType = MachO::N_EXT | MachO::N_ABS;
|
||||
S.TypeChar = 'A';
|
||||
} else if (ReExport) {
|
||||
S.NType = MachO::N_EXT | MachO::N_INDR;
|
||||
S.TypeChar = 'I';
|
||||
} else {
|
||||
S.NType = MachO::N_EXT | MachO::N_SECT;
|
||||
if (Resolver) {
|
||||
S.Address = Entry.other() + BaseSegmentAddress;
|
||||
if ((S.Address & 1) != 0 && !MachO.is64Bit() &&
|
||||
H.cputype == MachO::CPU_TYPE_ARM) {
|
||||
S.Address &= ~1LL;
|
||||
S.NDesc |= MachO::N_ARM_THUMB_DEF;
|
||||
}
|
||||
} else {
|
||||
S.Address = Entry.address() + BaseSegmentAddress;
|
||||
}
|
||||
StringRef SegmentName = StringRef();
|
||||
StringRef SectionName = StringRef();
|
||||
for (const SectionRef &Section : MachO.sections()) {
|
||||
S.NSect++;
|
||||
|
||||
if (Expected<StringRef> NameOrErr = Section.getName())
|
||||
SectionName = *NameOrErr;
|
||||
else
|
||||
consumeError(NameOrErr.takeError());
|
||||
|
||||
SegmentName =
|
||||
MachO.getSectionFinalSegmentName(Section.getRawDataRefImpl());
|
||||
if (S.Address >= Section.getAddress() &&
|
||||
S.Address < Section.getAddress() + Section.getSize()) {
|
||||
S.Section = Section;
|
||||
break;
|
||||
} else if (Entry.name() == "__mh_execute_header" &&
|
||||
SegmentName == "__TEXT" && SectionName == "__text") {
|
||||
S.Section = Section;
|
||||
S.NDesc |= MachO::REFERENCED_DYNAMICALLY;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (SegmentName == "__TEXT" && SectionName == "__text")
|
||||
S.TypeChar = 'T';
|
||||
else if (SegmentName == "__DATA" && SectionName == "__data")
|
||||
S.TypeChar = 'D';
|
||||
else if (SegmentName == "__DATA" && SectionName == "__bss")
|
||||
S.TypeChar = 'B';
|
||||
else
|
||||
S.TypeChar = 'S';
|
||||
}
|
||||
SymbolList.push_back(S);
|
||||
|
||||
EOS << Entry.name();
|
||||
EOS << '\0';
|
||||
ExportsAdded++;
|
||||
|
||||
// For ReExports there are a two more things to do, first add the
|
||||
// indirect name and second create the undefined symbol using the
|
||||
// referened dynamic library.
|
||||
if (ReExport) {
|
||||
|
||||
// Add the indirect name.
|
||||
if (Entry.otherName().empty())
|
||||
EOS << Entry.name();
|
||||
else
|
||||
EOS << Entry.otherName();
|
||||
EOS << '\0';
|
||||
|
||||
// Now create the undefined symbol using the referened dynamic
|
||||
// library.
|
||||
NMSymbol U = {};
|
||||
U.Address = 0;
|
||||
U.Size = 0;
|
||||
U.TypeChar = 'U';
|
||||
if (Entry.otherName().empty())
|
||||
U.Name = Entry.name().str();
|
||||
else
|
||||
U.Name = Entry.otherName().str();
|
||||
// Again there is no symbol in the nlist symbol table for this so
|
||||
// we set Sym effectivly to null and the rest of code in here must
|
||||
// test for it and not do things like Sym.getFlags() for it.
|
||||
U.Sym = BasicSymbolRef();
|
||||
U.SymFlags = SymbolRef::SF_Global | SymbolRef::SF_Undefined;
|
||||
U.Section = SectionRef();
|
||||
U.NType = MachO::N_EXT | MachO::N_UNDF;
|
||||
U.NSect = 0;
|
||||
U.NDesc = 0;
|
||||
// The library ordinal for this undefined symbol is in the export
|
||||
// trie Entry.other().
|
||||
MachO::SET_LIBRARY_ORDINAL(U.NDesc, Entry.other());
|
||||
SymbolList.push_back(U);
|
||||
|
||||
// Finally add the undefined symbol's name.
|
||||
if (Entry.otherName().empty())
|
||||
EOS << Entry.name();
|
||||
else
|
||||
EOS << Entry.otherName();
|
||||
EOS << '\0';
|
||||
ExportsAdded++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Err)
|
||||
error(std::move(Err), MachO.getFileName());
|
||||
// Set the symbol names and indirect names for the added symbols.
|
||||
if (ExportsAdded) {
|
||||
EOS.flush();
|
||||
const char *Q = ExportsNameBuffer.c_str();
|
||||
for (unsigned K = 0; K < ExportsAdded; K++) {
|
||||
SymbolList[I].Name = Q;
|
||||
Q += strlen(Q) + 1;
|
||||
if (SymbolList[I].TypeChar == 'I') {
|
||||
SymbolList[I].IndirectName = Q;
|
||||
Q += strlen(Q) + 1;
|
||||
}
|
||||
I++;
|
||||
}
|
||||
}
|
||||
|
||||
// Add the undefined symbols from the bind entries.
|
||||
unsigned BindsAdded = 0;
|
||||
Error BErr = Error::success();
|
||||
StringRef LastSymbolName = StringRef();
|
||||
for (const llvm::object::MachOBindEntry &Entry : MachO.bindTable(BErr)) {
|
||||
bool found = false;
|
||||
if (LastSymbolName == Entry.symbolName())
|
||||
found = true;
|
||||
else if (!DyldInfoOnly) {
|
||||
for (unsigned J = 0; J < SymbolList.size() && !found; ++J) {
|
||||
if (SymbolList[J].Name == Entry.symbolName())
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
LastSymbolName = Entry.symbolName();
|
||||
NMSymbol B = {};
|
||||
B.Address = 0;
|
||||
B.Size = 0;
|
||||
B.TypeChar = 'U';
|
||||
// There is no symbol in the nlist symbol table for this so we set
|
||||
// Sym effectivly to null and the rest of code in here must test for
|
||||
// it and not do things like Sym.getFlags() for it.
|
||||
B.Sym = BasicSymbolRef();
|
||||
B.SymFlags = SymbolRef::SF_Global | SymbolRef::SF_Undefined;
|
||||
B.NType = MachO::N_EXT | MachO::N_UNDF;
|
||||
B.NSect = 0;
|
||||
B.NDesc = 0;
|
||||
MachO::SET_LIBRARY_ORDINAL(B.NDesc, Entry.ordinal());
|
||||
B.Name = Entry.symbolName().str();
|
||||
SymbolList.push_back(B);
|
||||
BOS << Entry.symbolName();
|
||||
BOS << '\0';
|
||||
BindsAdded++;
|
||||
}
|
||||
}
|
||||
if (BErr)
|
||||
error(std::move(BErr), MachO.getFileName());
|
||||
// Set the symbol names and indirect names for the added symbols.
|
||||
if (BindsAdded) {
|
||||
BOS.flush();
|
||||
const char *Q = BindsNameBuffer.c_str();
|
||||
for (unsigned K = 0; K < BindsAdded; K++) {
|
||||
SymbolList[I].Name = Q;
|
||||
Q += strlen(Q) + 1;
|
||||
if (SymbolList[I].TypeChar == 'I') {
|
||||
SymbolList[I].IndirectName = Q;
|
||||
Q += strlen(Q) + 1;
|
||||
}
|
||||
I++;
|
||||
}
|
||||
}
|
||||
|
||||
// Add the undefined symbols from the lazy bind entries.
|
||||
unsigned LazysAdded = 0;
|
||||
Error LErr = Error::success();
|
||||
LastSymbolName = StringRef();
|
||||
for (const llvm::object::MachOBindEntry &Entry :
|
||||
MachO.lazyBindTable(LErr)) {
|
||||
bool found = false;
|
||||
if (LastSymbolName == Entry.symbolName())
|
||||
found = true;
|
||||
else {
|
||||
// Here we must check to see it this symbol is already in the
|
||||
// SymbolList as it might have already have been added above via a
|
||||
// non-lazy (bind) entry.
|
||||
for (unsigned J = 0; J < SymbolList.size() && !found; ++J) {
|
||||
if (SymbolList[J].Name == Entry.symbolName())
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
LastSymbolName = Entry.symbolName();
|
||||
NMSymbol L = {};
|
||||
L.Name = Entry.symbolName().str();
|
||||
L.Address = 0;
|
||||
L.Size = 0;
|
||||
L.TypeChar = 'U';
|
||||
// There is no symbol in the nlist symbol table for this so we set
|
||||
// Sym effectivly to null and the rest of code in here must test for
|
||||
// it and not do things like Sym.getFlags() for it.
|
||||
L.Sym = BasicSymbolRef();
|
||||
L.SymFlags = SymbolRef::SF_Global | SymbolRef::SF_Undefined;
|
||||
L.NType = MachO::N_EXT | MachO::N_UNDF;
|
||||
L.NSect = 0;
|
||||
// The REFERENCE_FLAG_UNDEFINED_LAZY is no longer used but here it
|
||||
// makes sence since we are creating this from a lazy bind entry.
|
||||
L.NDesc = MachO::REFERENCE_FLAG_UNDEFINED_LAZY;
|
||||
MachO::SET_LIBRARY_ORDINAL(L.NDesc, Entry.ordinal());
|
||||
SymbolList.push_back(L);
|
||||
LOS << Entry.symbolName();
|
||||
LOS << '\0';
|
||||
LazysAdded++;
|
||||
}
|
||||
}
|
||||
if (LErr)
|
||||
error(std::move(LErr), MachO.getFileName());
|
||||
// Set the symbol names and indirect names for the added symbols.
|
||||
if (LazysAdded) {
|
||||
LOS.flush();
|
||||
const char *Q = LazysNameBuffer.c_str();
|
||||
for (unsigned K = 0; K < LazysAdded; K++) {
|
||||
SymbolList[I].Name = Q;
|
||||
Q += strlen(Q) + 1;
|
||||
if (SymbolList[I].TypeChar == 'I') {
|
||||
SymbolList[I].IndirectName = Q;
|
||||
Q += strlen(Q) + 1;
|
||||
}
|
||||
I++;
|
||||
}
|
||||
}
|
||||
|
||||
// Add the undefineds symbol from the weak bind entries which are not
|
||||
// strong symbols.
|
||||
unsigned WeaksAdded = 0;
|
||||
Error WErr = Error::success();
|
||||
LastSymbolName = StringRef();
|
||||
for (const llvm::object::MachOBindEntry &Entry :
|
||||
MachO.weakBindTable(WErr)) {
|
||||
bool found = false;
|
||||
unsigned J = 0;
|
||||
if (LastSymbolName == Entry.symbolName() ||
|
||||
Entry.flags() & MachO::BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION) {
|
||||
found = true;
|
||||
} else {
|
||||
for (J = 0; J < SymbolList.size() && !found; ++J) {
|
||||
if (SymbolList[J].Name == Entry.symbolName()) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
LastSymbolName = Entry.symbolName();
|
||||
NMSymbol W = {};
|
||||
W.Name = Entry.symbolName().str();
|
||||
W.Address = 0;
|
||||
W.Size = 0;
|
||||
W.TypeChar = 'U';
|
||||
// There is no symbol in the nlist symbol table for this so we set
|
||||
// Sym effectivly to null and the rest of code in here must test for
|
||||
// it and not do things like Sym.getFlags() for it.
|
||||
W.Sym = BasicSymbolRef();
|
||||
W.SymFlags = SymbolRef::SF_Global | SymbolRef::SF_Undefined;
|
||||
W.NType = MachO::N_EXT | MachO::N_UNDF;
|
||||
W.NSect = 0;
|
||||
// Odd that we are using N_WEAK_DEF on an undefined symbol but that is
|
||||
// what is created in this case by the linker when there are real
|
||||
// symbols in the nlist structs.
|
||||
W.NDesc = MachO::N_WEAK_DEF;
|
||||
SymbolList.push_back(W);
|
||||
WOS << Entry.symbolName();
|
||||
WOS << '\0';
|
||||
WeaksAdded++;
|
||||
} else {
|
||||
// This is the case the symbol was previously been found and it could
|
||||
// have been added from a bind or lazy bind symbol. If so and not
|
||||
// a definition also mark it as weak.
|
||||
if (SymbolList[J].TypeChar == 'U')
|
||||
// See comment above about N_WEAK_DEF.
|
||||
SymbolList[J].NDesc |= MachO::N_WEAK_DEF;
|
||||
}
|
||||
}
|
||||
if (WErr)
|
||||
error(std::move(WErr), MachO.getFileName());
|
||||
// Set the symbol names and indirect names for the added symbols.
|
||||
if (WeaksAdded) {
|
||||
WOS.flush();
|
||||
const char *Q = WeaksNameBuffer.c_str();
|
||||
for (unsigned K = 0; K < WeaksAdded; K++) {
|
||||
SymbolList[I].Name = Q;
|
||||
Q += strlen(Q) + 1;
|
||||
if (SymbolList[I].TypeChar == 'I') {
|
||||
SymbolList[I].IndirectName = Q;
|
||||
Q += strlen(Q) + 1;
|
||||
}
|
||||
I++;
|
||||
}
|
||||
}
|
||||
|
||||
// Trying adding symbol from the function starts table and LC_MAIN entry
|
||||
// point.
|
||||
SmallVector<uint64_t, 8> FoundFns;
|
||||
uint64_t lc_main_offset = UINT64_MAX;
|
||||
for (const auto &Command : MachO.load_commands()) {
|
||||
if (Command.C.cmd == MachO::LC_FUNCTION_STARTS) {
|
||||
// We found a function starts segment, parse the addresses for
|
||||
// consumption.
|
||||
MachO::linkedit_data_command LLC =
|
||||
MachO.getLinkeditDataLoadCommand(Command);
|
||||
|
||||
MachO.ReadULEB128s(LLC.dataoff, FoundFns);
|
||||
} else if (Command.C.cmd == MachO::LC_MAIN) {
|
||||
MachO::entry_point_command LCmain = MachO.getEntryPointCommand(Command);
|
||||
lc_main_offset = LCmain.entryoff;
|
||||
}
|
||||
}
|
||||
// See if these addresses are already in the symbol table.
|
||||
unsigned FunctionStartsAdded = 0;
|
||||
for (uint64_t f = 0; f < FoundFns.size(); f++) {
|
||||
bool found = false;
|
||||
for (unsigned J = 0; J < SymbolList.size() && !found; ++J) {
|
||||
if (SymbolList[J].Address == FoundFns[f] + BaseSegmentAddress)
|
||||
found = true;
|
||||
}
|
||||
// See this address is not already in the symbol table fake up an
|
||||
// nlist for it.
|
||||
if (!found) {
|
||||
NMSymbol F = {};
|
||||
F.Name = "<redacted function X>";
|
||||
F.Address = FoundFns[f] + BaseSegmentAddress;
|
||||
F.Size = 0;
|
||||
// There is no symbol in the nlist symbol table for this so we set
|
||||
// Sym effectivly to null and the rest of code in here must test for
|
||||
// it and not do things like Sym.getFlags() for it.
|
||||
F.Sym = BasicSymbolRef();
|
||||
F.SymFlags = 0;
|
||||
F.NType = MachO::N_SECT;
|
||||
F.NSect = 0;
|
||||
StringRef SegmentName = StringRef();
|
||||
StringRef SectionName = StringRef();
|
||||
for (const SectionRef &Section : MachO.sections()) {
|
||||
if (Expected<StringRef> NameOrErr = Section.getName())
|
||||
SectionName = *NameOrErr;
|
||||
else
|
||||
consumeError(NameOrErr.takeError());
|
||||
|
||||
SegmentName =
|
||||
MachO.getSectionFinalSegmentName(Section.getRawDataRefImpl());
|
||||
F.NSect++;
|
||||
if (F.Address >= Section.getAddress() &&
|
||||
F.Address < Section.getAddress() + Section.getSize()) {
|
||||
F.Section = Section;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (SegmentName == "__TEXT" && SectionName == "__text")
|
||||
F.TypeChar = 't';
|
||||
else if (SegmentName == "__DATA" && SectionName == "__data")
|
||||
F.TypeChar = 'd';
|
||||
else if (SegmentName == "__DATA" && SectionName == "__bss")
|
||||
F.TypeChar = 'b';
|
||||
else
|
||||
F.TypeChar = 's';
|
||||
F.NDesc = 0;
|
||||
SymbolList.push_back(F);
|
||||
if (FoundFns[f] == lc_main_offset)
|
||||
FOS << "<redacted LC_MAIN>";
|
||||
else
|
||||
FOS << "<redacted function " << f << ">";
|
||||
FOS << '\0';
|
||||
FunctionStartsAdded++;
|
||||
}
|
||||
}
|
||||
if (FunctionStartsAdded) {
|
||||
FOS.flush();
|
||||
const char *Q = FunctionStartsNameBuffer.c_str();
|
||||
for (unsigned K = 0; K < FunctionStartsAdded; K++) {
|
||||
SymbolList[I].Name = Q;
|
||||
Q += strlen(Q) + 1;
|
||||
if (SymbolList[I].TypeChar == 'I') {
|
||||
SymbolList[I].IndirectName = Q;
|
||||
Q += strlen(Q) + 1;
|
||||
}
|
||||
I++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void dumpSymbolNamesFromObject(SymbolicFile &Obj, bool printName,
|
||||
StringRef ArchiveName = {},
|
||||
StringRef ArchitectureName = {}) {
|
||||
@ -1302,478 +1769,8 @@ static void dumpSymbolNamesFromObject(SymbolicFile &Obj, bool printName,
|
||||
// This is needed if strip(1) -T is run on a binary containing swift
|
||||
// language symbols for example. The option -only-dyldinfo will fake up
|
||||
// all symbols from the dyld export trie as well as the bind info.
|
||||
std::string ExportsNameBuffer;
|
||||
raw_string_ostream EOS(ExportsNameBuffer);
|
||||
std::string BindsNameBuffer;
|
||||
raw_string_ostream BOS(BindsNameBuffer);
|
||||
std::string LazysNameBuffer;
|
||||
raw_string_ostream LOS(LazysNameBuffer);
|
||||
std::string WeaksNameBuffer;
|
||||
raw_string_ostream WOS(WeaksNameBuffer);
|
||||
std::string FunctionStartsNameBuffer;
|
||||
raw_string_ostream FOS(FunctionStartsNameBuffer);
|
||||
if (MachO && !NoDyldInfo) {
|
||||
MachO::mach_header H;
|
||||
MachO::mach_header_64 H_64;
|
||||
uint32_t HFlags = 0;
|
||||
if (MachO->is64Bit()) {
|
||||
H_64 = MachO->MachOObjectFile::getHeader64();
|
||||
HFlags = H_64.flags;
|
||||
} else {
|
||||
H = MachO->MachOObjectFile::getHeader();
|
||||
HFlags = H.flags;
|
||||
}
|
||||
uint64_t BaseSegmentAddress = 0;
|
||||
for (const auto &Command : MachO->load_commands()) {
|
||||
if (Command.C.cmd == MachO::LC_SEGMENT) {
|
||||
MachO::segment_command Seg = MachO->getSegmentLoadCommand(Command);
|
||||
if (Seg.fileoff == 0 && Seg.filesize != 0) {
|
||||
BaseSegmentAddress = Seg.vmaddr;
|
||||
break;
|
||||
}
|
||||
} else if (Command.C.cmd == MachO::LC_SEGMENT_64) {
|
||||
MachO::segment_command_64 Seg = MachO->getSegment64LoadCommand(Command);
|
||||
if (Seg.fileoff == 0 && Seg.filesize != 0) {
|
||||
BaseSegmentAddress = Seg.vmaddr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (DyldInfoOnly || AddDyldInfo ||
|
||||
HFlags & MachO::MH_NLIST_OUTOFSYNC_WITH_DYLDINFO) {
|
||||
unsigned ExportsAdded = 0;
|
||||
Error Err = Error::success();
|
||||
for (const llvm::object::ExportEntry &Entry : MachO->exports(Err)) {
|
||||
bool found = false;
|
||||
bool ReExport = false;
|
||||
if (!DyldInfoOnly) {
|
||||
for (const NMSymbol &S : SymbolList)
|
||||
if (S.Address == Entry.address() + BaseSegmentAddress &&
|
||||
S.Name == Entry.name()) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
NMSymbol S = {};
|
||||
S.Address = Entry.address() + BaseSegmentAddress;
|
||||
S.Size = 0;
|
||||
S.TypeChar = '\0';
|
||||
S.Name = Entry.name();
|
||||
// There is no symbol in the nlist symbol table for this so we set
|
||||
// Sym effectivly to null and the rest of code in here must test for
|
||||
// it and not do things like Sym.getFlags() for it.
|
||||
S.Sym = BasicSymbolRef();
|
||||
S.SymFlags = SymbolRef::SF_Global;
|
||||
S.Section = SectionRef();
|
||||
S.NType = 0;
|
||||
S.NSect = 0;
|
||||
S.NDesc = 0;
|
||||
S.IndirectName = StringRef();
|
||||
|
||||
uint64_t EFlags = Entry.flags();
|
||||
bool Abs = ((EFlags & MachO::EXPORT_SYMBOL_FLAGS_KIND_MASK) ==
|
||||
MachO::EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE);
|
||||
bool Resolver = (EFlags &
|
||||
MachO::EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER);
|
||||
ReExport = (EFlags & MachO::EXPORT_SYMBOL_FLAGS_REEXPORT);
|
||||
bool WeakDef = (EFlags & MachO::EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION);
|
||||
if (WeakDef)
|
||||
S.NDesc |= MachO::N_WEAK_DEF;
|
||||
if (Abs) {
|
||||
S.NType = MachO::N_EXT | MachO::N_ABS;
|
||||
S.TypeChar = 'A';
|
||||
} else if (ReExport) {
|
||||
S.NType = MachO::N_EXT | MachO::N_INDR;
|
||||
S.TypeChar = 'I';
|
||||
} else {
|
||||
S.NType = MachO::N_EXT | MachO::N_SECT;
|
||||
if (Resolver) {
|
||||
S.Address = Entry.other() + BaseSegmentAddress;
|
||||
if ((S.Address & 1) != 0 &&
|
||||
!MachO->is64Bit() && H.cputype == MachO::CPU_TYPE_ARM){
|
||||
S.Address &= ~1LL;
|
||||
S.NDesc |= MachO::N_ARM_THUMB_DEF;
|
||||
}
|
||||
} else {
|
||||
S.Address = Entry.address() + BaseSegmentAddress;
|
||||
}
|
||||
StringRef SegmentName = StringRef();
|
||||
StringRef SectionName = StringRef();
|
||||
for (const SectionRef &Section : MachO->sections()) {
|
||||
S.NSect++;
|
||||
|
||||
if (Expected<StringRef> NameOrErr = Section.getName())
|
||||
SectionName = *NameOrErr;
|
||||
else
|
||||
consumeError(NameOrErr.takeError());
|
||||
|
||||
SegmentName = MachO->getSectionFinalSegmentName(
|
||||
Section.getRawDataRefImpl());
|
||||
if (S.Address >= Section.getAddress() &&
|
||||
S.Address < Section.getAddress() + Section.getSize()) {
|
||||
S.Section = Section;
|
||||
break;
|
||||
} else if (Entry.name() == "__mh_execute_header" &&
|
||||
SegmentName == "__TEXT" && SectionName == "__text") {
|
||||
S.Section = Section;
|
||||
S.NDesc |= MachO::REFERENCED_DYNAMICALLY;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (SegmentName == "__TEXT" && SectionName == "__text")
|
||||
S.TypeChar = 'T';
|
||||
else if (SegmentName == "__DATA" && SectionName == "__data")
|
||||
S.TypeChar = 'D';
|
||||
else if (SegmentName == "__DATA" && SectionName == "__bss")
|
||||
S.TypeChar = 'B';
|
||||
else
|
||||
S.TypeChar = 'S';
|
||||
}
|
||||
SymbolList.push_back(S);
|
||||
|
||||
EOS << Entry.name();
|
||||
EOS << '\0';
|
||||
ExportsAdded++;
|
||||
|
||||
// For ReExports there are a two more things to do, first add the
|
||||
// indirect name and second create the undefined symbol using the
|
||||
// referened dynamic library.
|
||||
if (ReExport) {
|
||||
|
||||
// Add the indirect name.
|
||||
if (Entry.otherName().empty())
|
||||
EOS << Entry.name();
|
||||
else
|
||||
EOS << Entry.otherName();
|
||||
EOS << '\0';
|
||||
|
||||
// Now create the undefined symbol using the referened dynamic
|
||||
// library.
|
||||
NMSymbol U = {};
|
||||
U.Address = 0;
|
||||
U.Size = 0;
|
||||
U.TypeChar = 'U';
|
||||
if (Entry.otherName().empty())
|
||||
U.Name = Entry.name();
|
||||
else
|
||||
U.Name = Entry.otherName();
|
||||
// Again there is no symbol in the nlist symbol table for this so
|
||||
// we set Sym effectivly to null and the rest of code in here must
|
||||
// test for it and not do things like Sym.getFlags() for it.
|
||||
U.Sym = BasicSymbolRef();
|
||||
U.SymFlags = SymbolRef::SF_Global | SymbolRef::SF_Undefined;
|
||||
U.Section = SectionRef();
|
||||
U.NType = MachO::N_EXT | MachO::N_UNDF;
|
||||
U.NSect = 0;
|
||||
U.NDesc = 0;
|
||||
// The library ordinal for this undefined symbol is in the export
|
||||
// trie Entry.other().
|
||||
MachO::SET_LIBRARY_ORDINAL(U.NDesc, Entry.other());
|
||||
U.IndirectName = StringRef();
|
||||
SymbolList.push_back(U);
|
||||
|
||||
// Finally add the undefined symbol's name.
|
||||
if (Entry.otherName().empty())
|
||||
EOS << Entry.name();
|
||||
else
|
||||
EOS << Entry.otherName();
|
||||
EOS << '\0';
|
||||
ExportsAdded++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Err)
|
||||
error(std::move(Err), MachO->getFileName());
|
||||
// Set the symbol names and indirect names for the added symbols.
|
||||
if (ExportsAdded) {
|
||||
EOS.flush();
|
||||
const char *Q = ExportsNameBuffer.c_str();
|
||||
for (unsigned K = 0; K < ExportsAdded; K++) {
|
||||
SymbolList[I].Name = Q;
|
||||
Q += strlen(Q) + 1;
|
||||
if (SymbolList[I].TypeChar == 'I') {
|
||||
SymbolList[I].IndirectName = Q;
|
||||
Q += strlen(Q) + 1;
|
||||
}
|
||||
I++;
|
||||
}
|
||||
}
|
||||
|
||||
// Add the undefined symbols from the bind entries.
|
||||
unsigned BindsAdded = 0;
|
||||
Error BErr = Error::success();
|
||||
StringRef LastSymbolName = StringRef();
|
||||
for (const llvm::object::MachOBindEntry &Entry : MachO->bindTable(BErr)) {
|
||||
bool found = false;
|
||||
if (LastSymbolName == Entry.symbolName())
|
||||
found = true;
|
||||
else if(!DyldInfoOnly) {
|
||||
for (unsigned J = 0; J < SymbolList.size() && !found; ++J) {
|
||||
if (SymbolList[J].Name == Entry.symbolName())
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
LastSymbolName = Entry.symbolName();
|
||||
NMSymbol B = {};
|
||||
B.Address = 0;
|
||||
B.Size = 0;
|
||||
B.TypeChar = 'U';
|
||||
// There is no symbol in the nlist symbol table for this so we set
|
||||
// Sym effectivly to null and the rest of code in here must test for
|
||||
// it and not do things like Sym.getFlags() for it.
|
||||
B.Sym = BasicSymbolRef();
|
||||
B.SymFlags = SymbolRef::SF_Global | SymbolRef::SF_Undefined;
|
||||
B.NType = MachO::N_EXT | MachO::N_UNDF;
|
||||
B.NSect = 0;
|
||||
B.NDesc = 0;
|
||||
MachO::SET_LIBRARY_ORDINAL(B.NDesc, Entry.ordinal());
|
||||
B.IndirectName = StringRef();
|
||||
B.Name = Entry.symbolName();
|
||||
SymbolList.push_back(B);
|
||||
BOS << Entry.symbolName();
|
||||
BOS << '\0';
|
||||
BindsAdded++;
|
||||
}
|
||||
}
|
||||
if (BErr)
|
||||
error(std::move(BErr), MachO->getFileName());
|
||||
// Set the symbol names and indirect names for the added symbols.
|
||||
if (BindsAdded) {
|
||||
BOS.flush();
|
||||
const char *Q = BindsNameBuffer.c_str();
|
||||
for (unsigned K = 0; K < BindsAdded; K++) {
|
||||
SymbolList[I].Name = Q;
|
||||
Q += strlen(Q) + 1;
|
||||
if (SymbolList[I].TypeChar == 'I') {
|
||||
SymbolList[I].IndirectName = Q;
|
||||
Q += strlen(Q) + 1;
|
||||
}
|
||||
I++;
|
||||
}
|
||||
}
|
||||
|
||||
// Add the undefined symbols from the lazy bind entries.
|
||||
unsigned LazysAdded = 0;
|
||||
Error LErr = Error::success();
|
||||
LastSymbolName = StringRef();
|
||||
for (const llvm::object::MachOBindEntry &Entry :
|
||||
MachO->lazyBindTable(LErr)) {
|
||||
bool found = false;
|
||||
if (LastSymbolName == Entry.symbolName())
|
||||
found = true;
|
||||
else {
|
||||
// Here we must check to see it this symbol is already in the
|
||||
// SymbolList as it might have already have been added above via a
|
||||
// non-lazy (bind) entry.
|
||||
for (unsigned J = 0; J < SymbolList.size() && !found; ++J) {
|
||||
if (SymbolList[J].Name == Entry.symbolName())
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
LastSymbolName = Entry.symbolName();
|
||||
NMSymbol L = {};
|
||||
L.Name = Entry.symbolName();
|
||||
L.Address = 0;
|
||||
L.Size = 0;
|
||||
L.TypeChar = 'U';
|
||||
// There is no symbol in the nlist symbol table for this so we set
|
||||
// Sym effectivly to null and the rest of code in here must test for
|
||||
// it and not do things like Sym.getFlags() for it.
|
||||
L.Sym = BasicSymbolRef();
|
||||
L.SymFlags = SymbolRef::SF_Global | SymbolRef::SF_Undefined;
|
||||
L.NType = MachO::N_EXT | MachO::N_UNDF;
|
||||
L.NSect = 0;
|
||||
// The REFERENCE_FLAG_UNDEFINED_LAZY is no longer used but here it
|
||||
// makes sence since we are creating this from a lazy bind entry.
|
||||
L.NDesc = MachO::REFERENCE_FLAG_UNDEFINED_LAZY;
|
||||
MachO::SET_LIBRARY_ORDINAL(L.NDesc, Entry.ordinal());
|
||||
L.IndirectName = StringRef();
|
||||
SymbolList.push_back(L);
|
||||
LOS << Entry.symbolName();
|
||||
LOS << '\0';
|
||||
LazysAdded++;
|
||||
}
|
||||
}
|
||||
if (LErr)
|
||||
error(std::move(LErr), MachO->getFileName());
|
||||
// Set the symbol names and indirect names for the added symbols.
|
||||
if (LazysAdded) {
|
||||
LOS.flush();
|
||||
const char *Q = LazysNameBuffer.c_str();
|
||||
for (unsigned K = 0; K < LazysAdded; K++) {
|
||||
SymbolList[I].Name = Q;
|
||||
Q += strlen(Q) + 1;
|
||||
if (SymbolList[I].TypeChar == 'I') {
|
||||
SymbolList[I].IndirectName = Q;
|
||||
Q += strlen(Q) + 1;
|
||||
}
|
||||
I++;
|
||||
}
|
||||
}
|
||||
|
||||
// Add the undefineds symbol from the weak bind entries which are not
|
||||
// strong symbols.
|
||||
unsigned WeaksAdded = 0;
|
||||
Error WErr = Error::success();
|
||||
LastSymbolName = StringRef();
|
||||
for (const llvm::object::MachOBindEntry &Entry :
|
||||
MachO->weakBindTable(WErr)) {
|
||||
bool found = false;
|
||||
unsigned J = 0;
|
||||
if (LastSymbolName == Entry.symbolName() ||
|
||||
Entry.flags() & MachO::BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION) {
|
||||
found = true;
|
||||
} else {
|
||||
for (J = 0; J < SymbolList.size() && !found; ++J) {
|
||||
if (SymbolList[J].Name == Entry.symbolName()) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
LastSymbolName = Entry.symbolName();
|
||||
NMSymbol W = {};
|
||||
W.Name = Entry.symbolName();
|
||||
W.Address = 0;
|
||||
W.Size = 0;
|
||||
W.TypeChar = 'U';
|
||||
// There is no symbol in the nlist symbol table for this so we set
|
||||
// Sym effectivly to null and the rest of code in here must test for
|
||||
// it and not do things like Sym.getFlags() for it.
|
||||
W.Sym = BasicSymbolRef();
|
||||
W.SymFlags = SymbolRef::SF_Global | SymbolRef::SF_Undefined;
|
||||
W.NType = MachO::N_EXT | MachO::N_UNDF;
|
||||
W.NSect = 0;
|
||||
// Odd that we are using N_WEAK_DEF on an undefined symbol but that is
|
||||
// what is created in this case by the linker when there are real
|
||||
// symbols in the nlist structs.
|
||||
W.NDesc = MachO::N_WEAK_DEF;
|
||||
W.IndirectName = StringRef();
|
||||
SymbolList.push_back(W);
|
||||
WOS << Entry.symbolName();
|
||||
WOS << '\0';
|
||||
WeaksAdded++;
|
||||
} else {
|
||||
// This is the case the symbol was previously been found and it could
|
||||
// have been added from a bind or lazy bind symbol. If so and not
|
||||
// a definition also mark it as weak.
|
||||
if (SymbolList[J].TypeChar == 'U')
|
||||
// See comment above about N_WEAK_DEF.
|
||||
SymbolList[J].NDesc |= MachO::N_WEAK_DEF;
|
||||
}
|
||||
}
|
||||
if (WErr)
|
||||
error(std::move(WErr), MachO->getFileName());
|
||||
// Set the symbol names and indirect names for the added symbols.
|
||||
if (WeaksAdded) {
|
||||
WOS.flush();
|
||||
const char *Q = WeaksNameBuffer.c_str();
|
||||
for (unsigned K = 0; K < WeaksAdded; K++) {
|
||||
SymbolList[I].Name = Q;
|
||||
Q += strlen(Q) + 1;
|
||||
if (SymbolList[I].TypeChar == 'I') {
|
||||
SymbolList[I].IndirectName = Q;
|
||||
Q += strlen(Q) + 1;
|
||||
}
|
||||
I++;
|
||||
}
|
||||
}
|
||||
|
||||
// Trying adding symbol from the function starts table and LC_MAIN entry
|
||||
// point.
|
||||
SmallVector<uint64_t, 8> FoundFns;
|
||||
uint64_t lc_main_offset = UINT64_MAX;
|
||||
for (const auto &Command : MachO->load_commands()) {
|
||||
if (Command.C.cmd == MachO::LC_FUNCTION_STARTS) {
|
||||
// We found a function starts segment, parse the addresses for
|
||||
// consumption.
|
||||
MachO::linkedit_data_command LLC =
|
||||
MachO->getLinkeditDataLoadCommand(Command);
|
||||
|
||||
MachO->ReadULEB128s(LLC.dataoff, FoundFns);
|
||||
} else if (Command.C.cmd == MachO::LC_MAIN) {
|
||||
MachO::entry_point_command LCmain =
|
||||
MachO->getEntryPointCommand(Command);
|
||||
lc_main_offset = LCmain.entryoff;
|
||||
}
|
||||
}
|
||||
// See if these addresses are already in the symbol table.
|
||||
unsigned FunctionStartsAdded = 0;
|
||||
for (uint64_t f = 0; f < FoundFns.size(); f++) {
|
||||
bool found = false;
|
||||
for (unsigned J = 0; J < SymbolList.size() && !found; ++J) {
|
||||
if (SymbolList[J].Address == FoundFns[f] + BaseSegmentAddress)
|
||||
found = true;
|
||||
}
|
||||
// See this address is not already in the symbol table fake up an
|
||||
// nlist for it.
|
||||
if (!found) {
|
||||
NMSymbol F = {};
|
||||
F.Name = "<redacted function X>";
|
||||
F.Address = FoundFns[f] + BaseSegmentAddress;
|
||||
F.Size = 0;
|
||||
// There is no symbol in the nlist symbol table for this so we set
|
||||
// Sym effectivly to null and the rest of code in here must test for
|
||||
// it and not do things like Sym.getFlags() for it.
|
||||
F.Sym = BasicSymbolRef();
|
||||
F.SymFlags = 0;
|
||||
F.NType = MachO::N_SECT;
|
||||
F.NSect = 0;
|
||||
StringRef SegmentName = StringRef();
|
||||
StringRef SectionName = StringRef();
|
||||
for (const SectionRef &Section : MachO->sections()) {
|
||||
if (Expected<StringRef> NameOrErr = Section.getName())
|
||||
SectionName = *NameOrErr;
|
||||
else
|
||||
consumeError(NameOrErr.takeError());
|
||||
|
||||
SegmentName = MachO->getSectionFinalSegmentName(
|
||||
Section.getRawDataRefImpl());
|
||||
F.NSect++;
|
||||
if (F.Address >= Section.getAddress() &&
|
||||
F.Address < Section.getAddress() + Section.getSize()) {
|
||||
F.Section = Section;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (SegmentName == "__TEXT" && SectionName == "__text")
|
||||
F.TypeChar = 't';
|
||||
else if (SegmentName == "__DATA" && SectionName == "__data")
|
||||
F.TypeChar = 'd';
|
||||
else if (SegmentName == "__DATA" && SectionName == "__bss")
|
||||
F.TypeChar = 'b';
|
||||
else
|
||||
F.TypeChar = 's';
|
||||
F.NDesc = 0;
|
||||
F.IndirectName = StringRef();
|
||||
SymbolList.push_back(F);
|
||||
if (FoundFns[f] == lc_main_offset)
|
||||
FOS << "<redacted LC_MAIN>";
|
||||
else
|
||||
FOS << "<redacted function " << f << ">";
|
||||
FOS << '\0';
|
||||
FunctionStartsAdded++;
|
||||
}
|
||||
}
|
||||
if (FunctionStartsAdded) {
|
||||
FOS.flush();
|
||||
const char *Q = FunctionStartsNameBuffer.c_str();
|
||||
for (unsigned K = 0; K < FunctionStartsAdded; K++) {
|
||||
SymbolList[I].Name = Q;
|
||||
Q += strlen(Q) + 1;
|
||||
if (SymbolList[I].TypeChar == 'I') {
|
||||
SymbolList[I].IndirectName = Q;
|
||||
Q += strlen(Q) + 1;
|
||||
}
|
||||
I++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (MachO && !NoDyldInfo)
|
||||
dumpSymbolsFromDLInfoMachO(*MachO);
|
||||
|
||||
CurrentFilename = Obj.getFileName();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user