Skip to content

Commit 4ac388f

Browse files
committed
[dsymutil] Fix handling of common symbols in multiple object files.
For common symbols the linker emits only a single symbol entry in the debug map. This caused dsymutil to not relocate common symbols when linking DWARF coming form object files that did not have this entry. This patch fixes that by keeping track of common symbols in the object files and synthesizing a debug map entry for them using the address from the main binary. Differential revision: https://reviews.llvm.org/D68680 llvm-svn: 374139
1 parent 0746aaf commit 4ac388f

File tree

5 files changed

+72
-2
lines changed

5 files changed

+72
-2
lines changed
Binary file not shown.
Binary file not shown.
Binary file not shown.
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
RUN: dsymutil -oso-prepend-path %p/../Inputs %p/../Inputs/private/tmp/common/com -f -o - | llvm-dwarfdump -debug-info - | FileCheck %s
2+
RUN: dsymutil -oso-prepend-path %p/../Inputs %p/../Inputs/private/tmp/common/com -dump-debug-map | FileCheck %s --check-prefix DEBUGMAP
3+
4+
The test was compiled from two source files:
5+
$ cd /private/tmp/common
6+
$ cat com1.c
7+
int i[1000];
8+
int main() {
9+
return i[1];
10+
}
11+
$ cat com2.c
12+
extern int i[1000];
13+
int bar() {
14+
return i[0];
15+
}
16+
$ clang -fcommon -g -c com1.c -o com1.o
17+
$ clang -fcommon -g -c com2.c -o com2.o
18+
$ clang -fcommon -g com1.o com2.o -o com
19+
20+
CHECK: DW_TAG_compile_unit
21+
CHECK: DW_TAG_variable
22+
CHECK-NOT: {{NULL|DW_TAG}}
23+
CHECK: DW_AT_name{{.*}}"i"
24+
CHECK-NOT: {{NULL|DW_TAG}}
25+
CHECK: DW_AT_location{{.*}}DW_OP_addr 0x100001000)
26+
27+
CHECK: DW_TAG_compile_unit
28+
CHECK: DW_TAG_variable
29+
CHECK-NOT: {{NULL|DW_TAG}}
30+
CHECK: DW_AT_name{{.*}}"i"
31+
CHECK-NOT: {{NULL|DW_TAG}}
32+
CHECK: DW_AT_location{{.*}}DW_OP_addr 0x100001000)
33+
34+
DEBUGMAP: filename:{{.*}}com1.o
35+
DEBUGMAP: symbols:
36+
DEBUGMAP: sym: _i, binAddr: 0x0000000100001000, size: 0x00000000
37+
DEBUGMAP: filename:{{.*}}com2.o
38+
DEBUGMAP: symbols:
39+
DEBUGMAP: sym: _i, binAddr: 0x0000000100001000, size: 0x00000000

llvm/tools/dsymutil/MachODebugMapParser.cpp

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "llvm/Support/Path.h"
1515
#include "llvm/Support/WithColor.h"
1616
#include "llvm/Support/raw_ostream.h"
17+
#include <vector>
1718

1819
namespace {
1920
using namespace llvm;
@@ -51,6 +52,8 @@ class MachODebugMapParser {
5152
StringRef MainBinaryStrings;
5253
/// The constructed DebugMap.
5354
std::unique_ptr<DebugMap> Result;
55+
/// List of common symbols that need to be added to the debug map.
56+
std::vector<std::string> CommonSymbols;
5457

5558
/// Map of the currently processed object file symbol addresses.
5659
StringMap<Optional<uint64_t>> CurrentObjectAddresses;
@@ -81,6 +84,8 @@ class MachODebugMapParser {
8184
STE.n_value);
8285
}
8386

87+
void addCommonSymbols();
88+
8489
/// Dump the symbol table output header.
8590
void dumpSymTabHeader(raw_ostream &OS, StringRef Arch);
8691

@@ -122,11 +127,32 @@ void MachODebugMapParser::resetParserState() {
122127
CurrentDebugMapObject = nullptr;
123128
}
124129

130+
/// Commons symbols won't show up in the symbol map but might need to be
131+
/// relocated. We can add them to the symbol table ourselves by combining the
132+
/// information in the object file (the symbol name) and the main binary (the
133+
/// address).
134+
void MachODebugMapParser::addCommonSymbols() {
135+
for (auto &CommonSymbol : CommonSymbols) {
136+
uint64_t CommonAddr = getMainBinarySymbolAddress(CommonSymbol);
137+
if (CommonAddr == 0) {
138+
// The main binary doesn't have an address for the given symbol.
139+
continue;
140+
}
141+
if (!CurrentDebugMapObject->addSymbol(CommonSymbol, None /*ObjectAddress*/,
142+
CommonAddr, 0 /*size*/)) {
143+
// The symbol is already present.
144+
continue;
145+
}
146+
}
147+
CommonSymbols.clear();
148+
}
149+
125150
/// Create a new DebugMapObject. This function resets the state of the
126151
/// parser that was referring to the last object file and sets
127152
/// everything up to add symbols to the new one.
128153
void MachODebugMapParser::switchToNewDebugMapObject(
129154
StringRef Filename, sys::TimePoint<std::chrono::seconds> Timestamp) {
155+
addCommonSymbols();
130156
resetParserState();
131157

132158
SmallString<80> Path(PathPrefix);
@@ -466,10 +492,15 @@ void MachODebugMapParser::loadCurrentObjectFileSymbols(
466492
// relocations will use the symbol itself, and won't need an
467493
// object file address. The object file address field is optional
468494
// in the DebugMap, leave it unassigned for these symbols.
469-
if (Sym.getFlags() & (SymbolRef::SF_Absolute | SymbolRef::SF_Common))
495+
uint32_t Flags = Sym.getFlags();
496+
if (Flags & SymbolRef::SF_Absolute) {
470497
CurrentObjectAddresses[*Name] = None;
471-
else
498+
} else if (Flags & SymbolRef::SF_Common) {
499+
CurrentObjectAddresses[*Name] = None;
500+
CommonSymbols.push_back(*Name);
501+
} else {
472502
CurrentObjectAddresses[*Name] = Addr;
503+
}
473504
}
474505
}
475506

0 commit comments

Comments
 (0)