Skip to content

Commit 8cf2f7a

Browse files
author
git apple-llvm automerger
committed
Merge commit 'f682bc0c3807' from swift/release/5.9 into stable/20221013
2 parents c3ba2c8 + f682bc0 commit 8cf2f7a

File tree

5 files changed

+119
-18
lines changed

5 files changed

+119
-18
lines changed
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
$ cat f.c
2+
int f() {
3+
volatile int i;
4+
return i;
5+
}
6+
$ cat g.c
7+
int g() {
8+
volatile int i;
9+
return i;
10+
}
11+
$ cat main.c
12+
int f();
13+
int g();
14+
15+
int main() {
16+
return f() + g();
17+
}
18+
$ clang -g f.c -c -o f/foo.o
19+
$ clang -g g.c -c -o g/foo.o
20+
$ libtool -static f/foo.o g/foo.o -o foo.a
21+
$ clang main.o foo.a -o main.out
22+
23+
RUN: dsymutil -oso-prepend-path %p/../Inputs %p/../Inputs/private/tmp/collision/main.out --dump-debug-map 2>&1 | FileCheck %s
24+
CHECK: skipping debug map object with duplicate name and timestamp: {{.*}} /private/tmp/collision/foo.a(foo.o)
25+
CHECK-NOT: could not find object file symbol for symbol _g
26+
CHECK-NOT: could not find object file symbol for symbol _f
Binary file not shown.
Binary file not shown.
Binary file not shown.

llvm/tools/dsymutil/MachODebugMapParser.cpp

Lines changed: 93 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,10 @@
99
#include "BinaryHolder.h"
1010
#include "DebugMap.h"
1111
#include "MachOUtils.h"
12-
#include "llvm/ADT/Optional.h"
12+
#include "llvm/ADT/DenseSet.h"
1313
#include "llvm/ADT/SmallSet.h"
1414
#include "llvm/Object/MachO.h"
15+
#include "llvm/Support/Chrono.h"
1516
#include "llvm/Support/Path.h"
1617
#include "llvm/Support/WithColor.h"
1718
#include "llvm/Support/raw_ostream.h"
@@ -31,7 +32,7 @@ class MachODebugMapParser {
3132
: BinaryPath(std::string(BinaryPath)), Archs(Archs.begin(), Archs.end()),
3233
PathPrefix(std::string(PathPrefix)),
3334
PaperTrailWarnings(PaperTrailWarnings), BinHolder(VFS, Verbose),
34-
CurrentDebugMapObject(nullptr) {}
35+
CurrentDebugMapObject(nullptr), SkipDebugMapObject(false) {}
3536

3637
/// Parses and returns the DebugMaps of the input binary. The binary contains
3738
/// multiple maps in case it is a universal binary.
@@ -42,6 +43,8 @@ class MachODebugMapParser {
4243
/// Walk the symbol table and dump it.
4344
bool dumpStab();
4445

46+
using OSO = std::pair<llvm::StringRef, uint64_t>;
47+
4548
private:
4649
std::string BinaryPath;
4750
SmallVector<StringRef, 1> Archs;
@@ -70,12 +73,18 @@ class MachODebugMapParser {
7073
/// Element of the debug map corresponding to the current object file.
7174
DebugMapObject *CurrentDebugMapObject;
7275

76+
/// Whether we need to skip the current debug map object.
77+
bool SkipDebugMapObject;
78+
7379
/// Holds function info while function scope processing.
7480
const char *CurrentFunctionName;
7581
uint64_t CurrentFunctionAddress;
7682

7783
std::unique_ptr<DebugMap> parseOneBinary(const MachOObjectFile &MainBinary,
7884
StringRef BinaryPath);
85+
void handleStabDebugMap(
86+
const MachOObjectFile &MainBinary,
87+
std::function<void(uint32_t, uint8_t, uint8_t, uint16_t, uint64_t)> F);
7988

8089
void
8190
switchToNewDebugMapObject(StringRef Filename,
@@ -85,13 +94,21 @@ class MachODebugMapParser {
8594
std::vector<StringRef> getMainBinarySymbolNames(uint64_t Value);
8695
void loadMainBinarySymbols(const MachOObjectFile &MainBinary);
8796
void loadCurrentObjectFileSymbols(const object::MachOObjectFile &Obj);
97+
98+
void handleStabOSOEntry(uint32_t StringIndex, uint8_t Type,
99+
uint8_t SectionIndex, uint16_t Flags, uint64_t Value,
100+
llvm::DenseSet<OSO> &OSOs,
101+
llvm::SmallSet<OSO, 4> &Duplicates);
88102
void handleStabSymbolTableEntry(uint32_t StringIndex, uint8_t Type,
89103
uint8_t SectionIndex, uint16_t Flags,
90-
uint64_t Value);
104+
uint64_t Value,
105+
const llvm::SmallSet<OSO, 4> &Duplicates);
91106

92-
template <typename STEType> void handleStabDebugMapEntry(const STEType &STE) {
93-
handleStabSymbolTableEntry(STE.n_strx, STE.n_type, STE.n_sect, STE.n_desc,
94-
STE.n_value);
107+
template <typename STEType>
108+
void handleStabDebugMapEntry(
109+
const STEType &STE,
110+
std::function<void(uint32_t, uint8_t, uint8_t, uint16_t, uint64_t)> F) {
111+
F(STE.n_strx, STE.n_type, STE.n_sect, STE.n_desc, STE.n_value);
95112
}
96113

97114
void addCommonSymbols();
@@ -140,6 +157,7 @@ void MachODebugMapParser::resetParserState() {
140157
CurrentObjectAliasMap.clear();
141158
SeenAliasValues.clear();
142159
CurrentDebugMapObject = nullptr;
160+
SkipDebugMapObject = false;
143161
}
144162

145163
/// Commons symbols won't show up in the symbol map but might need to be
@@ -198,21 +216,60 @@ static std::string getArchName(const object::MachOObjectFile &Obj) {
198216
return std::string(T.getArchName());
199217
}
200218

219+
void MachODebugMapParser::handleStabDebugMap(
220+
const MachOObjectFile &MainBinary,
221+
std::function<void(uint32_t, uint8_t, uint8_t, uint16_t, uint64_t)> F) {
222+
for (const SymbolRef &Symbol : MainBinary.symbols()) {
223+
const DataRefImpl &DRI = Symbol.getRawDataRefImpl();
224+
if (MainBinary.is64Bit())
225+
handleStabDebugMapEntry(MainBinary.getSymbol64TableEntry(DRI), F);
226+
else
227+
handleStabDebugMapEntry(MainBinary.getSymbolTableEntry(DRI), F);
228+
}
229+
}
230+
201231
std::unique_ptr<DebugMap>
202232
MachODebugMapParser::parseOneBinary(const MachOObjectFile &MainBinary,
203233
StringRef BinaryPath) {
204234
Result = std::make_unique<DebugMap>(MainBinary.getArchTriple(), BinaryPath,
205235
MainBinary.getUuid());
206236
loadMainBinarySymbols(MainBinary);
207237
MainBinaryStrings = MainBinary.getStringTableData();
208-
for (const SymbolRef &Symbol : MainBinary.symbols()) {
209-
const DataRefImpl &DRI = Symbol.getRawDataRefImpl();
210-
if (MainBinary.is64Bit())
211-
handleStabDebugMapEntry(MainBinary.getSymbol64TableEntry(DRI));
212-
else
213-
handleStabDebugMapEntry(MainBinary.getSymbolTableEntry(DRI));
238+
239+
// Static archives can contain multiple object files with identical names, in
240+
// which case the timestamp is used to disambiguate. However, if both are
241+
// identical, there's no way to tell them apart. Detect this and skip
242+
// duplicate debug map objects.
243+
llvm::DenseSet<OSO> OSOs;
244+
llvm::SmallSet<OSO, 4> Duplicates;
245+
246+
// Iterate over all the STABS to find duplicate OSO entries.
247+
handleStabDebugMap(MainBinary,
248+
[&](uint32_t StringIndex, uint8_t Type,
249+
uint8_t SectionIndex, uint16_t Flags, uint64_t Value) {
250+
handleStabOSOEntry(StringIndex, Type, SectionIndex,
251+
Flags, Value, OSOs, Duplicates);
252+
});
253+
254+
// Print an informative warning with the duplicate object file name and time
255+
// stamp.
256+
for (const auto &OSO : Duplicates) {
257+
std::string Buffer;
258+
llvm::raw_string_ostream OS(Buffer);
259+
OS << sys::TimePoint<std::chrono::seconds>(sys::toTimePoint(OSO.second));
260+
Warning("skipping debug map object with duplicate name and timestamp: " +
261+
OS.str() + Twine(" ") + Twine(OSO.first));
214262
}
215263

264+
// Build the debug map by iterating over the STABS again but ignore the
265+
// duplicate debug objects.
266+
handleStabDebugMap(MainBinary, [&](uint32_t StringIndex, uint8_t Type,
267+
uint8_t SectionIndex, uint16_t Flags,
268+
uint64_t Value) {
269+
handleStabSymbolTableEntry(StringIndex, Type, SectionIndex, Flags, Value,
270+
Duplicates);
271+
});
272+
216273
resetParserState();
217274
return std::move(Result);
218275
}
@@ -407,20 +464,38 @@ ErrorOr<std::vector<std::unique_ptr<DebugMap>>> MachODebugMapParser::parse() {
407464
return std::move(Results);
408465
}
409466

467+
void MachODebugMapParser::handleStabOSOEntry(
468+
uint32_t StringIndex, uint8_t Type, uint8_t SectionIndex, uint16_t Flags,
469+
uint64_t Value, llvm::DenseSet<OSO> &OSOs,
470+
llvm::SmallSet<OSO, 4> &Duplicates) {
471+
if (Type != MachO::N_OSO)
472+
return;
473+
474+
OSO O(&MainBinaryStrings.data()[StringIndex], Value);
475+
if (!OSOs.insert(O).second)
476+
Duplicates.insert(O);
477+
}
478+
410479
/// Interpret the STAB entries to fill the DebugMap.
411-
void MachODebugMapParser::handleStabSymbolTableEntry(uint32_t StringIndex,
412-
uint8_t Type,
413-
uint8_t SectionIndex,
414-
uint16_t Flags,
415-
uint64_t Value) {
480+
void MachODebugMapParser::handleStabSymbolTableEntry(
481+
uint32_t StringIndex, uint8_t Type, uint8_t SectionIndex, uint16_t Flags,
482+
uint64_t Value, const llvm::SmallSet<OSO, 4> &Duplicates) {
416483
if (!(Type & MachO::N_STAB))
417484
return;
418485

419486
const char *Name = &MainBinaryStrings.data()[StringIndex];
420487

421488
// An N_OSO entry represents the start of a new object file description.
422-
if (Type == MachO::N_OSO)
489+
if (Type == MachO::N_OSO) {
490+
if (Duplicates.count(OSO(Name, Value))) {
491+
SkipDebugMapObject = true;
492+
return;
493+
}
423494
return switchToNewDebugMapObject(Name, sys::toTimePoint(Value));
495+
}
496+
497+
if (SkipDebugMapObject)
498+
return;
424499

425500
if (Type == MachO::N_AST) {
426501
SmallString<80> Path(PathPrefix);

0 commit comments

Comments
 (0)