Skip to content

Commit bf0cda9

Browse files
alvinhochunmstorsjo
authored andcommitted
[lldb][COFF] Rewrite ParseSymtab to list both export and symbol tables
This reimplements `ObjectFilePECOFF::ParseSymtab` to replace the manual data extraction with what `COFFObjectFile` already provides. Also use `SymTab::AddSymbol` instead of resizing the SymTab then assigning each elements afterwards. Previously, ParseSymTab loads symbols from both the COFF symbol table and the export table, but if there are any entries in the export table, it overwrites all the symbols already loaded from the COFF symbol table. Due to the change to use AddSymbols, this no longer happens, and so the SymTab now contains all symbols from both tables as expected. The export symbols are now ordered by ordinal, instead of by the name table order. In its current state, it is possible for symbols in the COFF symbol table to be duplicated by those in the export table. This behaviour will be modified in a separate change. Reviewed By: labath Differential Revision: https://reviews.llvm.org/D134196
1 parent 759beda commit bf0cda9

File tree

4 files changed

+193
-142
lines changed

4 files changed

+193
-142
lines changed

lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp

Lines changed: 76 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,12 @@
3030
#include "lldb/Utility/StreamString.h"
3131
#include "lldb/Utility/Timer.h"
3232
#include "lldb/Utility/UUID.h"
33-
#include "llvm/BinaryFormat/COFF.h"
3433

34+
#include "llvm/BinaryFormat/COFF.h"
3535
#include "llvm/Object/COFFImportFile.h"
3636
#include "llvm/Support/CRC.h"
3737
#include "llvm/Support/Error.h"
38+
#include "llvm/Support/FormatAdapters.h"
3839
#include "llvm/Support/Host.h"
3940
#include "llvm/Support/MemoryBuffer.h"
4041

@@ -760,131 +761,93 @@ llvm::StringRef ObjectFilePECOFF::GetSectionName(const section_header_t &sect) {
760761

761762
void ObjectFilePECOFF::ParseSymtab(Symtab &symtab) {
762763
SectionList *sect_list = GetSectionList();
763-
const uint32_t num_syms = m_coff_header.nsyms;
764-
if (m_file && num_syms > 0 && m_coff_header.symoff > 0) {
765-
const uint32_t symbol_size = 18;
766-
const size_t symbol_data_size = num_syms * symbol_size;
767-
// Include the 4-byte string table size at the end of the symbols
768-
DataExtractor symtab_data =
769-
ReadImageData(m_coff_header.symoff, symbol_data_size + 4);
770-
lldb::offset_t offset = symbol_data_size;
771-
const uint32_t strtab_size = symtab_data.GetU32(&offset);
772-
if (strtab_size > 0) {
773-
DataExtractor strtab_data = ReadImageData(
774-
m_coff_header.symoff + symbol_data_size, strtab_size);
775-
776-
offset = 0;
777-
std::string symbol_name;
778-
Symbol *symbols = symtab.Resize(num_syms);
779-
for (uint32_t i = 0; i < num_syms; ++i) {
780-
coff_symbol_t symbol;
781-
const uint32_t symbol_offset = offset;
782-
const char *symbol_name_cstr = nullptr;
783-
// If the first 4 bytes of the symbol string are zero, then they
784-
// are followed by a 4-byte string table offset. Else these
785-
// 8 bytes contain the symbol name
786-
if (symtab_data.GetU32(&offset) == 0) {
787-
// Long string that doesn't fit into the symbol table name, so
788-
// now we must read the 4 byte string table offset
789-
uint32_t strtab_offset = symtab_data.GetU32(&offset);
790-
symbol_name_cstr = strtab_data.PeekCStr(strtab_offset);
791-
symbol_name.assign(symbol_name_cstr);
792-
} else {
793-
// Short string that fits into the symbol table name which is 8
794-
// bytes
795-
offset += sizeof(symbol.name) - 4; // Skip remaining
796-
symbol_name_cstr = symtab_data.PeekCStr(symbol_offset);
797-
if (symbol_name_cstr == nullptr)
798-
break;
799-
symbol_name.assign(symbol_name_cstr, sizeof(symbol.name));
800-
}
801-
symbol.value = symtab_data.GetU32(&offset);
802-
symbol.sect = symtab_data.GetU16(&offset);
803-
symbol.type = symtab_data.GetU16(&offset);
804-
symbol.storage = symtab_data.GetU8(&offset);
805-
symbol.naux = symtab_data.GetU8(&offset);
806-
symbols[i].GetMangled().SetValue(ConstString(symbol_name.c_str()));
807-
if ((int16_t)symbol.sect >= 1) {
808-
Address symbol_addr(sect_list->FindSectionByID(symbol.sect),
809-
symbol.value);
810-
symbols[i].GetAddressRef() = symbol_addr;
811-
symbols[i].SetType(MapSymbolType(symbol.type));
812-
}
764+
AppendFromExportTable(sect_list, symtab);
765+
AppendFromCOFFSymbolTable(sect_list, symtab);
766+
}
813767

814-
if (symbol.naux > 0) {
815-
i += symbol.naux;
816-
offset += symbol.naux * symbol_size;
817-
}
818-
}
768+
void ObjectFilePECOFF::AppendFromCOFFSymbolTable(SectionList *sect_list,
769+
Symtab &symtab) {
770+
const uint32_t num_syms = m_binary->getNumberOfSymbols();
771+
if (num_syms == 0)
772+
return;
773+
// Check that this is not a bigobj; we do not support bigobj.
774+
if (m_binary->getSymbolTableEntrySize() !=
775+
sizeof(llvm::object::coff_symbol16))
776+
return;
777+
778+
Log *log = GetLog(LLDBLog::Object);
779+
symtab.Reserve(symtab.GetNumSymbols() + num_syms);
780+
for (const auto &sym_ref : m_binary->symbols()) {
781+
const auto coff_sym_ref = m_binary->getCOFFSymbol(sym_ref);
782+
auto name_or_error = sym_ref.getName();
783+
if (auto err = name_or_error.takeError()) {
784+
LLDB_LOG(log,
785+
"ObjectFilePECOFF::AppendFromCOFFSymbolTable - failed to get "
786+
"symbol table entry name: {0}",
787+
llvm::fmt_consume(std::move(err)));
788+
continue;
789+
}
790+
const llvm::StringRef sym_name = *name_or_error;
791+
Symbol symbol;
792+
symbol.GetMangled().SetValue(ConstString(sym_name));
793+
int16_t section_number =
794+
static_cast<int16_t>(coff_sym_ref.getSectionNumber());
795+
if (section_number >= 1) {
796+
symbol.GetAddressRef() = Address(
797+
sect_list->FindSectionByID(section_number), coff_sym_ref.getValue());
798+
symbol.SetType(MapSymbolType(coff_sym_ref.getType()));
819799
}
800+
symtab.AddSymbol(symbol);
820801
}
802+
}
821803

822-
// Read export header
823-
if (coff_data_dir_export_table < m_coff_header_opt.data_dirs.size() &&
824-
m_coff_header_opt.data_dirs[coff_data_dir_export_table].vmsize > 0 &&
825-
m_coff_header_opt.data_dirs[coff_data_dir_export_table].vmaddr > 0) {
826-
export_directory_entry export_table;
827-
uint32_t data_start =
828-
m_coff_header_opt.data_dirs[coff_data_dir_export_table].vmaddr;
829-
830-
DataExtractor symtab_data = ReadImageDataByRVA(
831-
data_start, m_coff_header_opt.data_dirs[0].vmsize);
832-
lldb::offset_t offset = 0;
804+
void ObjectFilePECOFF::AppendFromExportTable(SectionList *sect_list,
805+
Symtab &symtab) {
806+
const auto *export_table = m_binary->getExportTable();
807+
if (!export_table)
808+
return;
809+
const uint32_t num_syms = export_table->AddressTableEntries;
810+
if (num_syms == 0)
811+
return;
833812

834-
// Read export_table header
835-
export_table.characteristics = symtab_data.GetU32(&offset);
836-
export_table.time_date_stamp = symtab_data.GetU32(&offset);
837-
export_table.major_version = symtab_data.GetU16(&offset);
838-
export_table.minor_version = symtab_data.GetU16(&offset);
839-
export_table.name = symtab_data.GetU32(&offset);
840-
export_table.base = symtab_data.GetU32(&offset);
841-
export_table.number_of_functions = symtab_data.GetU32(&offset);
842-
export_table.number_of_names = symtab_data.GetU32(&offset);
843-
export_table.address_of_functions = symtab_data.GetU32(&offset);
844-
export_table.address_of_names = symtab_data.GetU32(&offset);
845-
export_table.address_of_name_ordinals = symtab_data.GetU32(&offset);
846-
847-
bool has_ordinal = export_table.address_of_name_ordinals != 0;
848-
849-
lldb::offset_t name_offset = export_table.address_of_names - data_start;
850-
lldb::offset_t name_ordinal_offset =
851-
export_table.address_of_name_ordinals - data_start;
852-
853-
Symbol *symbols = symtab.Resize(export_table.number_of_names);
854-
855-
std::string symbol_name;
856-
857-
// Read each export table entry
858-
for (size_t i = 0; i < export_table.number_of_names; ++i) {
859-
uint32_t name_ordinal =
860-
has_ordinal ? symtab_data.GetU16(&name_ordinal_offset) : i;
861-
uint32_t name_address = symtab_data.GetU32(&name_offset);
862-
863-
const char *symbol_name_cstr =
864-
symtab_data.PeekCStr(name_address - data_start);
865-
symbol_name.assign(symbol_name_cstr);
866-
867-
lldb::offset_t function_offset = export_table.address_of_functions -
868-
data_start +
869-
sizeof(uint32_t) * name_ordinal;
870-
uint32_t function_rva = symtab_data.GetU32(&function_offset);
871-
872-
Address symbol_addr(m_coff_header_opt.image_base + function_rva,
873-
sect_list);
874-
symbols[i].GetMangled().SetValue(ConstString(symbol_name.c_str()));
875-
symbols[i].GetAddressRef() = symbol_addr;
876-
symbols[i].SetType(lldb::eSymbolTypeCode);
877-
symbols[i].SetDebug(true);
813+
Log *log = GetLog(LLDBLog::Object);
814+
symtab.Reserve(symtab.GetNumSymbols() + num_syms);
815+
// Read each export table entry, ordered by ordinal instead of by name.
816+
for (const auto &entry : m_binary->export_directories()) {
817+
llvm::StringRef sym_name;
818+
if (auto err = entry.getSymbolName(sym_name)) {
819+
LLDB_LOG(log,
820+
"ObjectFilePECOFF::AppendFromExportTable - failed to get export "
821+
"table entry name: {0}",
822+
llvm::fmt_consume(std::move(err)));
823+
continue;
824+
}
825+
Symbol symbol;
826+
// Note: symbol name may be empty if it is only exported by ordinal.
827+
symbol.GetMangled().SetValue(ConstString(sym_name));
828+
829+
uint32_t function_rva;
830+
if (auto err = entry.getExportRVA(function_rva)) {
831+
LLDB_LOG(log,
832+
"ObjectFilePECOFF::AppendFromExportTable - failed to get "
833+
"address of export entry '{0}': {1}",
834+
sym_name, llvm::fmt_consume(std::move(err)));
835+
continue;
878836
}
837+
symbol.GetAddressRef() =
838+
Address(m_coff_header_opt.image_base + function_rva, sect_list);
839+
symbol.SetType(lldb::eSymbolTypeCode);
840+
symbol.SetDebug(true);
841+
symtab.AddSymbol(symbol);
879842
}
880843
}
881844

882845
std::unique_ptr<CallFrameInfo> ObjectFilePECOFF::CreateCallFrameInfo() {
883-
if (coff_data_dir_exception_table >= m_coff_header_opt.data_dirs.size())
846+
if (llvm::COFF::EXCEPTION_TABLE >= m_coff_header_opt.data_dirs.size())
884847
return {};
885848

886849
data_directory data_dir_exception =
887-
m_coff_header_opt.data_dirs[coff_data_dir_exception_table];
850+
m_coff_header_opt.data_dirs[llvm::COFF::EXCEPTION_TABLE];
888851
if (!data_dir_exception.vmaddr)
889852
return {};
890853

lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h

Lines changed: 4 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -225,12 +225,6 @@ class ObjectFilePECOFF : public lldb_private::ObjectFile {
225225
data_dirs; // will contain num_data_dir_entries entries
226226
} coff_opt_header_t;
227227

228-
enum coff_data_dir_type {
229-
coff_data_dir_export_table = 0,
230-
coff_data_dir_import_table = 1,
231-
coff_data_dir_exception_table = 3
232-
};
233-
234228
typedef struct section_header {
235229
char name[8] = {};
236230
uint32_t vmsize = 0; // Virtual Size
@@ -244,29 +238,6 @@ class ObjectFilePECOFF : public lldb_private::ObjectFile {
244238
uint32_t flags = 0;
245239
} section_header_t;
246240

247-
typedef struct coff_symbol {
248-
char name[8] = {};
249-
uint32_t value = 0;
250-
uint16_t sect = 0;
251-
uint16_t type = 0;
252-
uint8_t storage = 0;
253-
uint8_t naux = 0;
254-
} coff_symbol_t;
255-
256-
typedef struct export_directory_entry {
257-
uint32_t characteristics = 0;
258-
uint32_t time_date_stamp = 0;
259-
uint16_t major_version = 0;
260-
uint16_t minor_version = 0;
261-
uint32_t name = 0;
262-
uint32_t base = 0;
263-
uint32_t number_of_functions = 0;
264-
uint32_t number_of_names = 0;
265-
uint32_t address_of_functions = 0;
266-
uint32_t address_of_names = 0;
267-
uint32_t address_of_name_ordinals = 0;
268-
} export_directory_entry;
269-
270241
static bool ParseDOSHeader(lldb_private::DataExtractor &data,
271242
dos_header_t &dos_header);
272243
static bool ParseCOFFHeader(lldb_private::DataExtractor &data,
@@ -297,6 +268,10 @@ class ObjectFilePECOFF : public lldb_private::ObjectFile {
297268

298269
private:
299270
bool CreateBinary();
271+
void AppendFromCOFFSymbolTable(lldb_private::SectionList *sect_list,
272+
lldb_private::Symtab &symtab);
273+
void AppendFromExportTable(lldb_private::SectionList *sect_list,
274+
lldb_private::Symtab &symtab);
300275

301276
dos_header_t m_dos_header;
302277
coff_header_t m_coff_header;
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
# RUN: yaml2obj %s -o %t
2+
# RUN: lldb-test symbols %t | FileCheck %s
3+
4+
# Checks that the symtab contains both symbols from the export table and the
5+
# COFF symbol table.
6+
7+
# CHECK: UserID DSX Type File Address/Value {{.*}} Size Flags Name
8+
# CHECK-NEXT: ------
9+
# CHECK-NEXT: 4294967295 D Code 0x0000000180001020 0x{{[0-9a-f]+}} 0x{{[0-9a-f]+}} exportFnAlias
10+
# CHECK-NEXT: 4294967295 D Code 0x0000000180001010 0x{{[0-9a-f]+}} 0x{{[0-9a-f]+}} exportFunc
11+
# CHECK-NEXT: 4294967295 D Code 0x0000000180003000 0x{{[0-9a-f]+}} 0x{{[0-9a-f]+}} exportInt
12+
# CHECK-NEXT: 4294967295 D Code 0x0000000180003004 0x{{[0-9a-f]+}} 0x{{[0-9a-f]+}} exportIntAlias
13+
# CHECK-NEXT: 4294967295 Code 0x0000000180001000 0x{{[0-9a-f]+}} 0x{{[0-9a-f]+}} entry
14+
# CHECK-NEXT: 4294967295 Code 0x0000000180001010 0x{{[0-9a-f]+}} 0x{{[0-9a-f]+}} exportFunc
15+
# CHECK-NEXT: 4294967295 Code 0x0000000180001020 0x{{[0-9a-f]+}} 0x{{[0-9a-f]+}} aliasFunc
16+
# CHECK-NEXT: 4294967295 Invalid 0x0000000180003000 0x{{[0-9a-f]+}} 0x{{[0-9a-f]+}} exportInt
17+
# CHECK-NEXT: 4294967295 Invalid 0x0000000180003004 0x{{[0-9a-f]+}} 0x{{[0-9a-f]+}} aliasInt
18+
# CHECK-NEXT: 4294967295 Invalid 0x0000000180003008 0x{{[0-9a-f]+}} 0x{{[0-9a-f]+}} internalInt
19+
# CHECK-EMPTY:
20+
21+
# Test file generated with:
22+
# clang -O2 --target=x86_64-windows-msvc test.c -nostdlib -c -o test.obj
23+
# lld-link -debug:symtab -dll -out:test.dll -entry:entry -export:exportFnAlias=aliasFunc -export:exportIntAlias=aliasInt test.obj
24+
# test.c:
25+
# __declspec(dllexport) int exportInt;
26+
# int aliasInt;
27+
# int internalInt;
28+
# void entry(void) {}
29+
# __declspec(dllexport) void exportFunc(void) {}
30+
# void aliasFunc(void) {}
31+
32+
--- !COFF
33+
OptionalHeader:
34+
AddressOfEntryPoint: 4096
35+
ImageBase: 6442450944
36+
SectionAlignment: 4096
37+
FileAlignment: 512
38+
MajorOperatingSystemVersion: 6
39+
MinorOperatingSystemVersion: 0
40+
MajorImageVersion: 0
41+
MinorImageVersion: 0
42+
MajorSubsystemVersion: 6
43+
MinorSubsystemVersion: 0
44+
Subsystem: IMAGE_SUBSYSTEM_WINDOWS_GUI
45+
DLLCharacteristics: [ IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA, IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE, IMAGE_DLL_CHARACTERISTICS_NX_COMPAT ]
46+
SizeOfStackReserve: 1048576
47+
SizeOfStackCommit: 4096
48+
SizeOfHeapReserve: 1048576
49+
SizeOfHeapCommit: 4096
50+
ExportTable:
51+
RelativeVirtualAddress: 8192
52+
Size: 156
53+
header:
54+
Machine: IMAGE_FILE_MACHINE_AMD64
55+
Characteristics: [ IMAGE_FILE_EXECUTABLE_IMAGE, IMAGE_FILE_LARGE_ADDRESS_AWARE, IMAGE_FILE_DLL ]
56+
sections:
57+
- Name: .text
58+
Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
59+
VirtualAddress: 4096
60+
VirtualSize: 33
61+
SectionData: C36666666666662E0F1F840000000000C36666666666662E0F1F840000000000C3
62+
- Name: .rdata
63+
Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
64+
VirtualAddress: 8192
65+
VirtualSize: 156
66+
SectionData: 0000000000000000000000002820000001000000040000000400000042200000522000006220000073796D626F6C732D6578706F7274732E632E746D702E646C6C00201000001010000000300000043000006A20000078200000832000008D20000000000100020003006578706F7274466E416C696173006578706F727446756E63006578706F7274496E74006578706F7274496E74416C69617300
67+
- Name: .data
68+
Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
69+
VirtualAddress: 12288
70+
VirtualSize: 12
71+
SectionData: ''
72+
symbols:
73+
- Name: entry
74+
Value: 0
75+
SectionNumber: 1
76+
SimpleType: IMAGE_SYM_TYPE_NULL
77+
ComplexType: IMAGE_SYM_DTYPE_FUNCTION
78+
StorageClass: IMAGE_SYM_CLASS_EXTERNAL
79+
- Name: exportFunc
80+
Value: 16
81+
SectionNumber: 1
82+
SimpleType: IMAGE_SYM_TYPE_NULL
83+
ComplexType: IMAGE_SYM_DTYPE_FUNCTION
84+
StorageClass: IMAGE_SYM_CLASS_EXTERNAL
85+
- Name: aliasFunc
86+
Value: 32
87+
SectionNumber: 1
88+
SimpleType: IMAGE_SYM_TYPE_NULL
89+
ComplexType: IMAGE_SYM_DTYPE_FUNCTION
90+
StorageClass: IMAGE_SYM_CLASS_EXTERNAL
91+
- Name: exportInt
92+
Value: 0
93+
SectionNumber: 3
94+
SimpleType: IMAGE_SYM_TYPE_NULL
95+
ComplexType: IMAGE_SYM_DTYPE_NULL
96+
StorageClass: IMAGE_SYM_CLASS_EXTERNAL
97+
- Name: aliasInt
98+
Value: 4
99+
SectionNumber: 3
100+
SimpleType: IMAGE_SYM_TYPE_NULL
101+
ComplexType: IMAGE_SYM_DTYPE_NULL
102+
StorageClass: IMAGE_SYM_CLASS_EXTERNAL
103+
- Name: internalInt
104+
Value: 8
105+
SectionNumber: 3
106+
SimpleType: IMAGE_SYM_TYPE_NULL
107+
ComplexType: IMAGE_SYM_DTYPE_NULL
108+
StorageClass: IMAGE_SYM_CLASS_EXTERNAL
109+
...

llvm/include/llvm/Object/COFF.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -914,6 +914,10 @@ class COFFObjectFile : public ObjectFile {
914914

915915
uint32_t getStringTableSize() const { return StringTableSize; }
916916

917+
const export_directory_table_entry *getExportTable() const {
918+
return ExportDirectory;
919+
}
920+
917921
const coff_load_configuration32 *getLoadConfig32() const {
918922
assert(!is64());
919923
return reinterpret_cast<const coff_load_configuration32 *>(LoadConfig);

0 commit comments

Comments
 (0)