diff options
author | Greg Clayton <gclayton@apple.com> | 2013-10-21 18:40:51 +0000 |
---|---|---|
committer | Greg Clayton <gclayton@apple.com> | 2013-10-21 18:40:51 +0000 |
commit | 9191db47dad0032653b024330c1f496f6cdee918 (patch) | |
tree | a8bc588a9d615ffc209dba07c4fc843d0ac3b7a8 /lldb/source/Plugins/ObjectFile | |
parent | f46e5f1c9a75fa22d13c50e51c6b2e6158f9e825 (diff) | |
download | bcm5719-llvm-9191db47dad0032653b024330c1f496f6cdee918.tar.gz bcm5719-llvm-9191db47dad0032653b024330c1f496f6cdee918.zip |
<rdar://problem/14496092>
Fixed an issue with reexported symbols on MacOSX by adding support for symbols re-exporting symbols. There is now a new symbol type eSymbolTypeReExported which contains a new name for the re-exported symbol and the new shared library. These symbols are only used when a symbol is re-exported as a symbol under a different name.
Modified the expression parser to be able to deal with finding the re-exported symbols and track down the actual symbol it refers to.
llvm-svn: 193101
Diffstat (limited to 'lldb/source/Plugins/ObjectFile')
-rw-r--r-- | lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp | 275 |
1 files changed, 240 insertions, 35 deletions
diff --git a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp index 36652310470..a11ca26a9ad 100644 --- a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp +++ b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp @@ -894,6 +894,7 @@ ObjectFileMachO::GetAddressClass (lldb::addr_t file_addr) case eSymbolTypeObjCClass: return eAddressClassRuntime; case eSymbolTypeObjCMetaClass: return eAddressClassRuntime; case eSymbolTypeObjCIVar: return eAddressClassRuntime; + case eSymbolTypeReExported: return eAddressClassRuntime; } } } @@ -1481,6 +1482,138 @@ protected: std::vector<SectionInfo> m_section_infos; }; +struct TrieEntry +{ + TrieEntry () : + name(), + address(LLDB_INVALID_ADDRESS), + flags (0), + other(0), + import_name() + { + } + + void + Clear () + { + name.Clear(); + address = LLDB_INVALID_ADDRESS; + flags = 0; + other = 0; + import_name.Clear(); + } + + void + Dump () const + { + printf ("0x%16.16llx 0x%16.16llx 0x%16.16llx \"%s\"", address, flags, other, name.GetCString()); + if (import_name) + printf (" -> \"%s\"\n", import_name.GetCString()); + else + printf ("\n"); + } + ConstString name; + uint64_t address; + uint64_t flags; + uint64_t other; + ConstString import_name; +}; + +struct TrieEntryWithOffset +{ + lldb::offset_t nodeOffset; + TrieEntry entry; + + TrieEntryWithOffset (lldb::offset_t offset) : + nodeOffset (offset), + entry() + { + } + + void + Dump (uint32_t idx) const + { + printf ("[%3u] 0x%16.16llx: ", idx, nodeOffset); + entry.Dump(); + } + + bool + operator<(const TrieEntryWithOffset& other) const + { + return ( nodeOffset < other.nodeOffset ); + } +}; + +static void +ParseTrieEntries (DataExtractor &data, + lldb::offset_t offset, + std::vector<llvm::StringRef> &nameSlices, + std::set<lldb::addr_t> &resolver_addresses, + std::vector<TrieEntryWithOffset>& output) +{ + if (!data.ValidOffset(offset)) + return; + + const uint64_t terminalSize = data.GetULEB128(&offset); + lldb::offset_t children_offset = offset + terminalSize; + if ( terminalSize != 0 ) { + TrieEntryWithOffset e (offset); + e.entry.flags = data.GetULEB128(&offset); + const char *import_name = NULL; + if ( e.entry.flags & EXPORT_SYMBOL_FLAGS_REEXPORT ) { + e.entry.address = 0; + e.entry.other = data.GetULEB128(&offset); // dylib ordinal + import_name = data.GetCStr(&offset); + } + else { + e.entry.address = data.GetULEB128(&offset); + if ( e.entry.flags & EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER ) + { + resolver_addresses.insert(e.entry.address); + e.entry.other = data.GetULEB128(&offset); + } + else + e.entry.other = 0; + } + // Only add symbols that are reexport symbols with a valid import name + if (EXPORT_SYMBOL_FLAGS_REEXPORT & e.entry.flags && import_name && import_name[0]) + { + std::string name; + if (!nameSlices.empty()) + { + for (auto name_slice: nameSlices) + name.append(name_slice.data(), name_slice.size()); + } + if (name.size() > 1) + { + // Skip the leading '_' + e.entry.name.SetCStringWithLength(name.c_str() + 1,name.size() - 1); + } + if (import_name) + { + // Skip the leading '_' + e.entry.import_name.SetCString(import_name+1); + } + output.push_back(e); + } + } + + const uint8_t childrenCount = data.GetU8(&children_offset); + for (uint8_t i=0; i < childrenCount; ++i) { + nameSlices.push_back(data.GetCStr(&children_offset)); + lldb::offset_t childNodeOffset = data.GetULEB128(&children_offset); + if (childNodeOffset) + { + ParseTrieEntries(data, + childNodeOffset, + nameSlices, + resolver_addresses, + output); + } + nameSlices.pop_back(); + } +} + size_t ObjectFileMachO::ParseSymtab () { @@ -1493,11 +1626,12 @@ ObjectFileMachO::ParseSymtab () struct symtab_command symtab_load_command = { 0, 0, 0, 0, 0, 0 }; struct linkedit_data_command function_starts_load_command = { 0, 0, 0, 0 }; + struct dyld_info_command dyld_info = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; typedef AddressDataArray<lldb::addr_t, bool, 100> FunctionStarts; FunctionStarts function_starts; lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic); uint32_t i; - + FileSpecList dylib_files; Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SYMBOLS)); for (i=0; i<m_header.ncmds; ++i) @@ -1545,6 +1679,39 @@ ObjectFileMachO::ParseSymtab () } break; + case LC_DYLD_INFO: + case LC_DYLD_INFO_ONLY: + if (m_data.GetU32(&offset, &dyld_info.rebase_off, 10)) + { + dyld_info.cmd = lc.cmd; + dyld_info.cmdsize = lc.cmdsize; + } + else + { + memset (&dyld_info, 0, sizeof(dyld_info)); + } + break; + + case LC_LOAD_DYLIB: + case LC_LOAD_WEAK_DYLIB: + case LC_REEXPORT_DYLIB: + case LC_LOADFVMLIB: + case LC_LOAD_UPWARD_DYLIB: + { + uint32_t name_offset = cmd_offset + m_data.GetU32(&offset); + const char *path = m_data.PeekCStr(name_offset); + if (path) + { + FileSpec file_spec(path, false); + // Strip the path if there is @rpath, @executanble, etc so we just use the basename + if (path[0] == '@') + file_spec.GetDirectory().Clear(); + + dylib_files.Append(file_spec); + } + } + break; + case LC_FUNCTION_STARTS: function_starts_load_command.cmd = lc.cmd; function_starts_load_command.cmdsize = lc.cmdsize; @@ -1574,6 +1741,7 @@ ObjectFileMachO::ParseSymtab () DataExtractor strtab_data (NULL, 0, byte_order, addr_byte_size); DataExtractor function_starts_data (NULL, 0, byte_order, addr_byte_size); DataExtractor indirect_symbol_index_data (NULL, 0, byte_order, addr_byte_size); + DataExtractor dyld_trie_data (NULL, 0, byte_order, addr_byte_size); const addr_t nlist_data_byte_size = symtab_load_command.nsyms * nlist_byte_size; const addr_t strtab_data_byte_size = symtab_load_command.strsize; @@ -1689,6 +1857,14 @@ ObjectFileMachO::ParseSymtab () strtab_data.SetData (m_data, symtab_load_command.stroff, strtab_data_byte_size); + + if (dyld_info.export_size > 0) + { + dyld_trie_data.SetData (m_data, + dyld_info.export_off, + dyld_info.export_size); + } + if (m_dysymtab.nindirectsyms != 0) { indirect_symbol_index_data.SetData (m_data, @@ -2661,6 +2837,7 @@ ObjectFileMachO::ParseSymtab () m_nlist_idx_to_sym_idx[nlist_idx] = pos->second; // We just need the flags from the linker symbol, so put these flags // into the N_FUN flags to avoid duplicate symbols in the symbol table + sym[pos->second].SetExternal(sym[sym_idx].IsExternal()); sym[pos->second].SetFlags (nlist.n_type << 16 | nlist.n_desc); sym[sym_idx].Clear(); continue; @@ -2681,6 +2858,7 @@ ObjectFileMachO::ParseSymtab () m_nlist_idx_to_sym_idx[nlist_idx] = pos->second; // We just need the flags from the linker symbol, so put these flags // into the N_STSYM flags to avoid duplicate symbols in the symbol table + sym[pos->second].SetExternal(sym[sym_idx].IsExternal()); sym[pos->second].SetFlags (nlist.n_type << 16 | nlist.n_desc); sym[sym_idx].Clear(); continue; @@ -3404,6 +3582,7 @@ ObjectFileMachO::ParseSymtab () m_nlist_idx_to_sym_idx[nlist_idx] = pos->second; // We just need the flags from the linker symbol, so put these flags // into the N_FUN flags to avoid duplicate symbols in the symbol table + sym[pos->second].SetExternal(sym[sym_idx].IsExternal()); sym[pos->second].SetFlags (nlist.n_type << 16 | nlist.n_desc); sym[sym_idx].Clear(); continue; @@ -3424,6 +3603,7 @@ ObjectFileMachO::ParseSymtab () m_nlist_idx_to_sym_idx[nlist_idx] = pos->second; // We just need the flags from the linker symbol, so put these flags // into the N_STSYM flags to avoid duplicate symbols in the symbol table + sym[pos->second].SetExternal(sym[sym_idx].IsExternal()); sym[pos->second].SetFlags (nlist.n_type << 16 | nlist.n_desc); sym[sym_idx].Clear(); continue; @@ -3469,38 +3649,6 @@ ObjectFileMachO::ParseSymtab () { sym[sym_idx].Clear(); } - - } - - // STAB N_GSYM entries end up having a symbol type eSymbolTypeGlobal and when the symbol value - // is zero, the address of the global ends up being in a non-STAB entry. Try and fix up all - // such entries by figuring out what the address for the global is by looking up this non-STAB - // entry and copying the value into the debug symbol's value to save us the hassle in the - // debug symbol parser. - - Symbol *global_symbol = NULL; - for (nlist_idx = 0; - nlist_idx < symtab_load_command.nsyms && (global_symbol = symtab->FindSymbolWithType (eSymbolTypeData, Symtab::eDebugYes, Symtab::eVisibilityAny, nlist_idx)) != NULL; - nlist_idx++) - { - if (global_symbol->GetAddress().GetFileAddress() == 0) - { - std::vector<uint32_t> indexes; - if (symtab->AppendSymbolIndexesWithName (global_symbol->GetMangled().GetName(), indexes) > 0) - { - std::vector<uint32_t>::const_iterator pos; - std::vector<uint32_t>::const_iterator end = indexes.end(); - for (pos = indexes.begin(); pos != end; ++pos) - { - symbol_ptr = symtab->SymbolAtIndex(*pos); - if (symbol_ptr != global_symbol && symbol_ptr->IsDebug() == false) - { - global_symbol->GetAddress() = symbol_ptr->GetAddress(); - break; - } - } - } - } } } @@ -3588,6 +3736,31 @@ ObjectFileMachO::ParseSymtab () sym = symtab->Resize (num_syms); } + std::vector<TrieEntryWithOffset> trie_entries; + std::set<lldb::addr_t> resolver_addresses; + + if (dyld_trie_data.GetByteSize() > 0) + { + std::vector<llvm::StringRef> nameSlices; + ParseTrieEntries (dyld_trie_data, + 0, + nameSlices, + resolver_addresses, + trie_entries); + + ConstString text_segment_name ("__TEXT"); + SectionSP text_segment_sp = GetSectionList()->FindSectionByName(text_segment_name); + if (text_segment_sp) + { + const lldb::addr_t text_segment_file_addr = text_segment_sp->GetFileAddress(); + if (text_segment_file_addr != LLDB_INVALID_ADDRESS) + { + for (auto &e : trie_entries) + e.entry.address += text_segment_file_addr; + } + } + } + // Now synthesize indirect symbols if (m_dysymtab.nindirectsyms != 0) { @@ -3646,7 +3819,10 @@ ObjectFileMachO::ParseSymtab () // These symbols were N_UNDF N_EXT, and are useless to us, so we // can re-use them so we don't have to make up a synthetic symbol // for no good reason. - stub_symbol->SetType (eSymbolTypeTrampoline); + if (resolver_addresses.find(symbol_stub_addr) == resolver_addresses.end()) + stub_symbol->SetType (eSymbolTypeTrampoline); + else + stub_symbol->SetType (eSymbolTypeResolver); stub_symbol->SetExternal (false); stub_symbol->GetAddress() = so_addr; stub_symbol->SetByteSize (symbol_stub_byte_size); @@ -3662,7 +3838,10 @@ ObjectFileMachO::ParseSymtab () } sym[sym_idx].SetID (synthetic_sym_id++); sym[sym_idx].GetMangled() = stub_symbol_mangled_name; - sym[sym_idx].SetType (eSymbolTypeTrampoline); + if (resolver_addresses.find(symbol_stub_addr) == resolver_addresses.end()) + sym[sym_idx].SetType (eSymbolTypeTrampoline); + else + sym[sym_idx].SetType (eSymbolTypeResolver); sym[sym_idx].SetIsSynthetic (true); sym[sym_idx].GetAddress() = so_addr; sym[sym_idx].SetByteSize (symbol_stub_byte_size); @@ -3680,6 +3859,32 @@ ObjectFileMachO::ParseSymtab () } } } + + + if (!trie_entries.empty()) + { + for (const auto &e : trie_entries) + { + if (e.entry.import_name) + { + // Make a synthetic symbol to describe re-exported symbol. + if (sym_idx >= num_syms) + sym = symtab->Resize (++num_syms); + sym[sym_idx].SetID (synthetic_sym_id++); + sym[sym_idx].GetMangled() = Mangled(e.entry.name); + sym[sym_idx].SetType (eSymbolTypeReExported); + sym[sym_idx].SetIsSynthetic (true); + sym[sym_idx].SetReExportedSymbolName(e.entry.import_name); + if (e.entry.other > 0 && e.entry.other <= dylib_files.GetSize()) + { + sym[sym_idx].SetReExportedSymbolSharedLibrary(dylib_files.GetFileSpecAtIndex(e.entry.other-1)); + } + ++sym_idx; + } + } + } + + // StreamFile s(stdout, false); // s.Printf ("Symbol table before CalculateSymbolSizes():\n"); |