[llvm] d8e86a5 - [dsymutil] Add option to filter debug map objects by allow/disallow-list (#182083)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Mar 4 12:57:03 PST 2026
Author: Roy Shi
Date: 2026-03-04T12:56:58-08:00
New Revision: d8e86a5cc0d5f0775faf5fc039a0c27e16dbdd61
URL: https://github.com/llvm/llvm-project/commit/d8e86a5cc0d5f0775faf5fc039a0c27e16dbdd61
DIFF: https://github.com/llvm/llvm-project/commit/d8e86a5cc0d5f0775faf5fc039a0c27e16dbdd61.diff
LOG: [dsymutil] Add option to filter debug map objects by allow/disallow-list (#182083)
# Motivation
When using `dsymutil` to generate dSYM for large binaries, sometimes we
want to keep only some of the object files. This has the benefits of
reduced dSYM size and improved performance of LLDB and other tools which
consume the dSYM.
The current way to achieve this is to use YAML input (the `dsymutil -y`
option). However, it doesn't really solve the problem:
1. The whole debug map has to be parsed somewhere else first, before
filtered down to the wanted parts.
2. Said info is written then read by `dsymutil`. The I/O is redundant.
# Change
This patch propose a new way, by adding new options (`dsymutil --allow
<path>` and `--disallow <path>`), which will only process object files
that pass the allow/disallow list.
Important details:
* The input file is YAML. See test files for format.
* Currently, only object files are filtered. The design allows to extend
the filtering to other aspects of the debug map in the future (e.g.
functions).
* If `--oso-prepend-path` is specified, it applies to the entries in the
input file. I.e. Entries in the input file should exact match that of
N_OSO entries.
Added:
llvm/test/tools/dsymutil/AArch64/allow-disallow.test
llvm/test/tools/dsymutil/Inputs/allow-disallow/a.out.arm64
llvm/test/tools/dsymutil/Inputs/allow-disallow/empty.yaml
llvm/test/tools/dsymutil/Inputs/allow-disallow/one.yaml
llvm/test/tools/dsymutil/Inputs/allow-disallow/two.yaml
llvm/test/tools/dsymutil/Inputs/private/tmp/allow-disallow/1.o
llvm/test/tools/dsymutil/Inputs/private/tmp/allow-disallow/2.o
llvm/test/tools/dsymutil/Inputs/private/tmp/allow-disallow/3.o
Modified:
llvm/docs/CommandGuide/dsymutil.rst
llvm/test/tools/dsymutil/cmdline.test
llvm/tools/dsymutil/DebugMap.cpp
llvm/tools/dsymutil/DebugMap.h
llvm/tools/dsymutil/MachODebugMapParser.cpp
llvm/tools/dsymutil/Options.td
llvm/tools/dsymutil/dsymutil.cpp
llvm/tools/dsymutil/dsymutil.h
Removed:
################################################################################
diff --git a/llvm/docs/CommandGuide/dsymutil.rst b/llvm/docs/CommandGuide/dsymutil.rst
index 0e442d657e987..c40cd18f32d19 100644
--- a/llvm/docs/CommandGuide/dsymutil.rst
+++ b/llvm/docs/CommandGuide/dsymutil.rst
@@ -23,6 +23,12 @@ OPTIONS
Specify the desired type of accelerator table. Valid options are 'Apple',
'Dwarf', 'Default' and 'None'.
+.. option:: --allow <path>
+
+ Only process debug map objects listed in the YAML file at <path>. Only filters
+ N_OSO entries. If `--oso-prepend-path` is specified, the path prefix applies,
+ i.e. paths in the file should exact match that of N_OSO entries.
+
.. option:: --arch <arch>
Link DWARF debug information only for specified CPU architecture types.
@@ -40,6 +46,12 @@ OPTIONS
'profile'. Setting the DYLD_IMAGE_SUFFIX environment variable will
cause dyld to load the specified variant at runtime.
+.. option:: --disallow <path>
+
+ Exclude debug map objects listed in the YAML file at <path>. Only filters
+ N_OSO entries. If `--oso-prepend-path` is specified, the path prefix applies,
+ i.e. paths in the file should exact match that of N_OSO entries.
+
.. option:: --dump-debug-map
Dump the *executable*'s debug-map (the list of the object files containing the
diff --git a/llvm/test/tools/dsymutil/AArch64/allow-disallow.test b/llvm/test/tools/dsymutil/AArch64/allow-disallow.test
new file mode 100644
index 0000000000000..b496829e7b6a1
--- /dev/null
+++ b/llvm/test/tools/dsymutil/AArch64/allow-disallow.test
@@ -0,0 +1,105 @@
+# Test --allow to include one object file (1.o).
+RUN: dsymutil --dump-debug-map \
+RUN: %p/../Inputs/allow-disallow/a.out.arm64 \
+RUN: --oso-prepend-path=%p/../Inputs \
+RUN: --allow=%p/../Inputs/allow-disallow/one.yaml \
+RUN: | FileCheck %s --check-prefix=ALLOW-ONE
+
+# Test --allow to include two object files (1.o and 3.o).
+RUN: dsymutil --dump-debug-map \
+RUN: %p/../Inputs/allow-disallow/a.out.arm64 \
+RUN: --oso-prepend-path=%p/../Inputs \
+RUN: --allow=%p/../Inputs/allow-disallow/two.yaml \
+RUN: | FileCheck %s --check-prefix=ALLOW-TWO
+
+# Test --allow to include no object files (empty allow list).
+RUN: dsymutil --dump-debug-map \
+RUN: %p/../Inputs/allow-disallow/a.out.arm64 \
+RUN: --oso-prepend-path=%p/../Inputs \
+RUN: --allow=%p/../Inputs/allow-disallow/empty.yaml \
+RUN: | FileCheck %s --check-prefix=ALLOW-NONE
+
+# Test --disallow to exclude one object file (1.o).
+RUN: dsymutil --dump-debug-map \
+RUN: %p/../Inputs/allow-disallow/a.out.arm64 \
+RUN: --oso-prepend-path=%p/../Inputs \
+RUN: --disallow=%p/../Inputs/allow-disallow/one.yaml \
+RUN: | FileCheck %s --check-prefix=DISALLOW-ONE
+
+# Test --disallow to exclude two object files (1.o and 3.o).
+RUN: dsymutil --dump-debug-map \
+RUN: %p/../Inputs/allow-disallow/a.out.arm64 \
+RUN: --oso-prepend-path=%p/../Inputs \
+RUN: --disallow=%p/../Inputs/allow-disallow/two.yaml \
+RUN: | FileCheck %s --check-prefix=DISALLOW-TWO
+
+# Test --disallow to exclude no object files (empty allow list).
+RUN: dsymutil --dump-debug-map \
+RUN: %p/../Inputs/allow-disallow/a.out.arm64 \
+RUN: --oso-prepend-path=%p/../Inputs \
+RUN: --disallow=%p/../Inputs/allow-disallow/empty.yaml \
+RUN: | FileCheck %s --check-prefix=DISALLOW-NONE
+
+# Test error when allow-list file does not exist.
+RUN: not dsymutil --dump-debug-map \
+RUN: %p/../Inputs/allow-disallow/a.out.arm64 \
+RUN: --allow=/nonexistent/path 2>&1 \
+RUN: | FileCheck %s --check-prefix=MISSING-FILE
+
+# Test error when disallow-list file does not exist.
+RUN: not dsymutil --dump-debug-map \
+RUN: %p/../Inputs/allow-disallow/a.out.arm64 \
+RUN: --disallow=/nonexistent/path 2>&1 \
+RUN: | FileCheck %s --check-prefix=MISSING-FILE
+
+# Test error when combined with -y.
+RUN: not dsymutil --allow=some.file.yaml \
+RUN: -y %p/../Inputs/remarks/basic.macho.remarks.arm64 2>&1 \
+RUN: | FileCheck %s --check-prefix=YAML-CONFLICT
+
+# Test error when --allow and --disallow are both specified.
+RUN: not dsymutil --allow=some.file.yaml --disallow=some.file.yaml \
+RUN: %p/../Inputs/allow-disallow/a.out.arm64 2>&1 \
+RUN: | FileCheck %s --check-prefix=ALLOW-DISALLOW-CONFLICT
+
+ALLOW-ONE: ---
+ALLOW-ONE: filename: {{.*}}1.o
+ALLOW-ONE-NOT: filename:
+ALLOW-ONE: ...
+
+ALLOW-TWO: ---
+ALLOW-TWO: filename: {{.*}}1.o
+ALLOW-TWO-NOT: filename: {{.*}}2.o
+ALLOW-TWO: filename: {{.*}}3.o
+ALLOW-TWO-NOT: filename:
+ALLOW-TWO: ...
+
+ALLOW-NONE: ---
+ALLOW-NONE-NOT: filename:
+ALLOW-NONE: ...
+
+DISALLOW-ONE: ---
+DISALLOW-ONE-NOT: filename: {{.*}}1.o
+DISALLOW-ONE: filename: {{.*}}2.o
+DISALLOW-ONE: filename: {{.*}}3.o
+DISALLOW-ONE-NOT: filename:
+DISALLOW-ONE: ...
+
+DISALLOW-TWO: ---
+DISALLOW-TWO-NOT: filename: {{.*}}1.o
+DISALLOW-TWO: filename: {{.*}}2.o
+DISALLOW-TWO-NOT: filename: {{.*}}3.o
+DISALLOW-TWO-NOT: filename:
+DISALLOW-TWO: ...
+
+DISALLOW-NONE: ---
+DISALLOW-NONE: filename: {{.*}}1.o
+DISALLOW-NONE: filename: {{.*}}2.o
+DISALLOW-NONE: filename: {{.*}}3.o
+DISALLOW-NONE: ...
+
+MISSING-FILE: error: cannot open allow/disallow file
+
+YAML-CONFLICT: error: -y and --allow/--disallow cannot be specified together
+
+ALLOW-DISALLOW-CONFLICT: error: --allow and --disallow cannot be specified together
diff --git a/llvm/test/tools/dsymutil/Inputs/allow-disallow/a.out.arm64 b/llvm/test/tools/dsymutil/Inputs/allow-disallow/a.out.arm64
new file mode 100755
index 0000000000000..c321e003b722d
Binary files /dev/null and b/llvm/test/tools/dsymutil/Inputs/allow-disallow/a.out.arm64
diff er
diff --git a/llvm/test/tools/dsymutil/Inputs/allow-disallow/empty.yaml b/llvm/test/tools/dsymutil/Inputs/allow-disallow/empty.yaml
new file mode 100644
index 0000000000000..013bc460dee1c
--- /dev/null
+++ b/llvm/test/tools/dsymutil/Inputs/allow-disallow/empty.yaml
@@ -0,0 +1,2 @@
+objects:
+...
diff --git a/llvm/test/tools/dsymutil/Inputs/allow-disallow/one.yaml b/llvm/test/tools/dsymutil/Inputs/allow-disallow/one.yaml
new file mode 100644
index 0000000000000..177c16828b87a
--- /dev/null
+++ b/llvm/test/tools/dsymutil/Inputs/allow-disallow/one.yaml
@@ -0,0 +1,3 @@
+objects:
+ - filename: '/private/tmp/allow-disallow/1.o'
+...
diff --git a/llvm/test/tools/dsymutil/Inputs/allow-disallow/two.yaml b/llvm/test/tools/dsymutil/Inputs/allow-disallow/two.yaml
new file mode 100644
index 0000000000000..e464ced4d0dd9
--- /dev/null
+++ b/llvm/test/tools/dsymutil/Inputs/allow-disallow/two.yaml
@@ -0,0 +1,4 @@
+objects:
+ - filename: '/private/tmp/allow-disallow/1.o'
+ - filename: '/private/tmp/allow-disallow/3.o'
+...
diff --git a/llvm/test/tools/dsymutil/Inputs/private/tmp/allow-disallow/1.o b/llvm/test/tools/dsymutil/Inputs/private/tmp/allow-disallow/1.o
new file mode 100644
index 0000000000000..4451a6ddc1518
Binary files /dev/null and b/llvm/test/tools/dsymutil/Inputs/private/tmp/allow-disallow/1.o
diff er
diff --git a/llvm/test/tools/dsymutil/Inputs/private/tmp/allow-disallow/2.o b/llvm/test/tools/dsymutil/Inputs/private/tmp/allow-disallow/2.o
new file mode 100644
index 0000000000000..afc80bc913912
Binary files /dev/null and b/llvm/test/tools/dsymutil/Inputs/private/tmp/allow-disallow/2.o
diff er
diff --git a/llvm/test/tools/dsymutil/Inputs/private/tmp/allow-disallow/3.o b/llvm/test/tools/dsymutil/Inputs/private/tmp/allow-disallow/3.o
new file mode 100644
index 0000000000000..4ab34d0dde819
Binary files /dev/null and b/llvm/test/tools/dsymutil/Inputs/private/tmp/allow-disallow/3.o
diff er
diff --git a/llvm/test/tools/dsymutil/cmdline.test b/llvm/test/tools/dsymutil/cmdline.test
index 0b0bce194d575..7b815f6ef232c 100644
--- a/llvm/test/tools/dsymutil/cmdline.test
+++ b/llvm/test/tools/dsymutil/cmdline.test
@@ -6,8 +6,10 @@ HELP: USAGE: {{.*}}dsymutil{{[^ ]*}} [options] <input files>
HELP-NOT: -reverse-iterate
HELP: Dsymutil Options:
CHECK: -accelerator
+CHECK: -allow <path>
CHECK: -arch <arch>
CHECK: -build-variant-suffix <suffix=buildvariant>
+CHECK: -disallow <path>
CHECK: -dump-debug-map
CHECK: -D <path>
CHECK: -fat64
@@ -52,3 +54,6 @@ BOGUS: warning: ignoring unknown option: -bogus
RUN: not dsymutil --quiet --verbose 2>&1 | FileCheck --check-prefix=CONFLICT %s
CONFLICT: error: --quiet and --verbose cannot be specified together
+
+RUN: not dsymutil -y file1 --allow file2 2>&1 | FileCheck --check-prefix=CONFLICT2 %s
+CONFLICT2: error: -y and --allow/--disallow cannot be specified together
diff --git a/llvm/tools/dsymutil/DebugMap.cpp b/llvm/tools/dsymutil/DebugMap.cpp
index 8798601754ff4..220666cf0af48 100644
--- a/llvm/tools/dsymutil/DebugMap.cpp
+++ b/llvm/tools/dsymutil/DebugMap.cpp
@@ -40,7 +40,7 @@ using namespace llvm::object;
DebugMapObject::DebugMapObject(StringRef ObjectFilename,
sys::TimePoint<std::chrono::seconds> Timestamp,
uint8_t Type)
- : Filename(std::string(ObjectFilename)), Timestamp(Timestamp), Type(Type) {}
+ : DebugMapObjectFilter(ObjectFilename), Timestamp(Timestamp), Type(Type) {}
bool DebugMapObject::addSymbol(StringRef Name,
std::optional<uint64_t> ObjectAddress,
@@ -94,8 +94,9 @@ DebugMapObject &
DebugMap::addDebugMapObject(StringRef ObjectFilePath,
sys::TimePoint<std::chrono::seconds> Timestamp,
uint8_t Type) {
- Objects.emplace_back(new DebugMapObject(ObjectFilePath, Timestamp, Type));
- return *Objects.back();
+ getObjects().emplace_back(
+ new DebugMapObject(ObjectFilePath, Timestamp, Type));
+ return *getObjects().back();
}
const DebugMapObject::DebugMapEntry *
@@ -123,6 +124,9 @@ void DebugMap::print(raw_ostream &OS) const {
void DebugMap::dump() const { print(errs()); }
#endif
+DebugMapObjectFilter::DebugMapObjectFilter(StringRef ObjectFilename)
+ : Filename(std::string(ObjectFilename)) {}
+
namespace {
struct YAMLContext {
@@ -219,6 +223,26 @@ SequenceTraits<std::vector<std::unique_ptr<dsymutil::DebugMapObject>>>::element(
return *seq[index];
}
+size_t
+SequenceTraits<std::vector<std::unique_ptr<dsymutil::DebugMapObjectFilter>>>::
+ size(IO &io,
+ std::vector<std::unique_ptr<dsymutil::DebugMapObjectFilter>> &seq) {
+ return seq.size();
+}
+
+dsymutil::DebugMapObject &
+SequenceTraits<std::vector<std::unique_ptr<dsymutil::DebugMapObjectFilter>>>::
+ element(IO &io,
+ std::vector<std::unique_ptr<dsymutil::DebugMapObjectFilter>> &seq,
+ size_t index) {
+ auto &Objects = reinterpret_cast<
+ std::vector<std::unique_ptr<dsymutil::DebugMapObject>> &>(seq);
+ return SequenceTraits<
+ std::vector<std::unique_ptr<dsymutil::DebugMapObject>>>::element(io,
+ Objects,
+ index);
+}
+
void MappingTraits<dsymutil::DebugMap>::mapping(IO &io,
dsymutil::DebugMap &DM) {
io.mapRequired("triple", DM.BinaryTriple);
diff --git a/llvm/tools/dsymutil/DebugMap.h b/llvm/tools/dsymutil/DebugMap.h
index 9a518222a56da..27d4d318017fd 100644
--- a/llvm/tools/dsymutil/DebugMap.h
+++ b/llvm/tools/dsymutil/DebugMap.h
@@ -48,6 +48,12 @@ class raw_ostream;
namespace dsymutil {
class DebugMapObject;
+class DebugMapObjectFilter;
+
+class DebugMapFilter {
+protected:
+ std::vector<std::unique_ptr<DebugMapObjectFilter>> Objects;
+};
/// The DebugMap object stores the list of object files to query for debug
/// information along with the mapping between the symbols' addresses in the
@@ -73,13 +79,18 @@ class DebugMapObject;
/// DIE.discardSubtree();
/// }
/// }
-class DebugMap {
+class DebugMap : public DebugMapFilter {
Triple BinaryTriple;
std::string BinaryPath;
std::vector<uint8_t> BinaryUUID;
using ObjectContainer = std::vector<std::unique_ptr<DebugMapObject>>;
- ObjectContainer Objects;
+ ObjectContainer &getObjects() {
+ return reinterpret_cast<ObjectContainer &>(Objects);
+ }
+ const ObjectContainer &getObjects() const {
+ return reinterpret_cast<const ObjectContainer &>(Objects);
+ }
/// For YAML IO support.
///@{
@@ -99,9 +110,9 @@ class DebugMap {
return make_range(begin(), end());
}
- const_iterator begin() const { return Objects.begin(); }
+ const_iterator begin() const { return getObjects().begin(); }
- const_iterator end() const { return Objects.end(); }
+ const_iterator end() const { return getObjects().end(); }
unsigned getNumberOfObjects() const { return Objects.size(); }
@@ -130,10 +141,37 @@ class DebugMap {
StringRef PrependPath, bool Verbose);
};
+class DebugMapObjectFilter {
+public:
+ StringRef getObjectFilename() const { return Filename; }
+
+protected:
+ std::string Filename;
+
+private:
+ friend class DebugMapFilter;
+ friend class DebugMapObject;
+
+ DebugMapObjectFilter(StringRef ObjectFilename);
+
+ /// For YAMLIO support.
+ ///@{
+ friend yaml::MappingTraits<dsymutil::DebugMapObjectFilter>;
+ friend yaml::SequenceTraits<
+ std::vector<std::unique_ptr<DebugMapObjectFilter>>>;
+
+ DebugMapObjectFilter() = default;
+
+public:
+ DebugMapObjectFilter(DebugMapObjectFilter &&) = default;
+ DebugMapObjectFilter &operator=(DebugMapObjectFilter &&) = default;
+ ///@}
+};
+
/// The DebugMapObject represents one object file described by the DebugMap. It
/// contains a list of mappings between addresses in the object file and in the
/// linked binary for all the linked atoms in this object file.
-class DebugMapObject {
+class DebugMapObject : public DebugMapObjectFilter {
public:
using YAMLSymbolMapping = std::pair<std::string, SymbolMapping>;
using DebugMapEntry = StringMapEntry<SymbolMapping>;
@@ -152,8 +190,6 @@ class DebugMapObject {
/// \returns null if the address isn't found.
const DebugMapEntry *lookupObjectAddress(uint64_t Address) const;
- StringRef getObjectFilename() const { return Filename; }
-
sys::TimePoint<std::chrono::seconds> getTimestamp() const {
return Timestamp;
}
@@ -189,7 +225,6 @@ class DebugMapObject {
DebugMapObject(StringRef ObjectFilename,
sys::TimePoint<std::chrono::seconds> Timestamp, uint8_t Type);
- std::string Filename;
sys::TimePoint<std::chrono::seconds> Timestamp;
StringMap<struct SymbolMapping> Symbols;
DenseMap<uint64_t, DebugMapEntry *> AddressToMapping;
@@ -242,6 +277,18 @@ struct SequenceTraits<std::vector<std::unique_ptr<dsymutil::DebugMapObject>>> {
size_t index);
};
+template <>
+struct SequenceTraits<
+ std::vector<std::unique_ptr<dsymutil::DebugMapObjectFilter>>> {
+ static size_t
+ size(IO &io,
+ std::vector<std::unique_ptr<dsymutil::DebugMapObjectFilter>> &seq);
+ static dsymutil::DebugMapObject &
+ element(IO &,
+ std::vector<std::unique_ptr<dsymutil::DebugMapObjectFilter>> &seq,
+ size_t index);
+};
+
template <> struct MappingTraits<dsymutil::DebugMap> {
static void mapping(IO &io, dsymutil::DebugMap &DM);
};
diff --git a/llvm/tools/dsymutil/MachODebugMapParser.cpp b/llvm/tools/dsymutil/MachODebugMapParser.cpp
index a0ba2512e12f2..4ce1aa90879c0 100644
--- a/llvm/tools/dsymutil/MachODebugMapParser.cpp
+++ b/llvm/tools/dsymutil/MachODebugMapParser.cpp
@@ -10,8 +10,10 @@
#include "DebugMap.h"
#include "MachOUtils.h"
#include "RelocationMap.h"
+#include "dsymutil.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/SmallSet.h"
+#include "llvm/ADT/StringSet.h"
#include "llvm/Object/MachO.h"
#include "llvm/Support/Chrono.h"
#include "llvm/Support/Path.h"
@@ -27,15 +29,18 @@ using namespace llvm::object;
class MachODebugMapParser {
public:
- MachODebugMapParser(BinaryHolder &BinHolder, StringRef BinaryPath,
- ArrayRef<std::string> Archs,
- ArrayRef<std::string> DSYMSearchPaths,
- StringRef PathPrefix = "", StringRef VariantSuffix = "",
- bool Verbose = false)
+ MachODebugMapParser(
+ BinaryHolder &BinHolder, StringRef BinaryPath,
+ ArrayRef<std::string> Archs, ArrayRef<std::string> DSYMSearchPaths,
+ StringRef PathPrefix = "", StringRef VariantSuffix = "",
+ bool Verbose = false,
+ const std::optional<StringSet<>> &ObjectFilter = std::nullopt,
+ ObjectFilterType ObjectFilterType = ObjectFilterType::Allow)
: BinaryPath(std::string(BinaryPath)), Archs(Archs),
DSYMSearchPaths(DSYMSearchPaths), PathPrefix(std::string(PathPrefix)),
VariantSuffix(std::string(VariantSuffix)), BinHolder(BinHolder),
- CurrentDebugMapObject(nullptr), SkipDebugMapObject(false) {}
+ CurrentDebugMapObject(nullptr), SkipDebugMapObject(false),
+ ObjectFilter(ObjectFilter), ObjectFilterType(ObjectFilterType) {}
/// Parses and returns the DebugMaps of the input binary. The binary contains
/// multiple maps in case it is a universal binary.
@@ -80,6 +85,12 @@ class MachODebugMapParser {
/// Whether we need to skip the current debug map object.
bool SkipDebugMapObject;
+ /// Optional set of object paths to filter on.
+ const std::optional<StringSet<>> &ObjectFilter;
+
+ /// Whether ObjectFilter is an allow list or a disallow list.
+ enum ObjectFilterType ObjectFilterType;
+
/// Holds function info while function scope processing.
const char *CurrentFunctionName;
uint64_t CurrentFunctionAddress;
@@ -120,6 +131,15 @@ class MachODebugMapParser {
void addCommonSymbols();
+ /// Check if a debug map object should be included based on the
+ /// object filter.
+ bool shouldIncludeObject(StringRef Path) const {
+ if (!ObjectFilter.has_value())
+ return true;
+ bool InSet = ObjectFilter->contains(Path);
+ return ObjectFilterType == Allow ? InSet : !InSet;
+ }
+
/// Dump the symbol table output header.
void dumpSymTabHeader(raw_ostream &OS, StringRef Arch);
@@ -191,6 +211,11 @@ void MachODebugMapParser::switchToNewDebugMapObject(
SmallString<80> Path(PathPrefix);
sys::path::append(Path, Filename);
+ if (!shouldIncludeObject(Path)) {
+ SkipDebugMapObject = true;
+ return;
+ }
+
auto ObjectEntry = BinHolder.getObjectEntry(Path, Timestamp);
if (!ObjectEntry) {
auto Err = ObjectEntry.takeError();
@@ -857,13 +882,16 @@ llvm::ErrorOr<std::vector<std::unique_ptr<DebugMap>>>
parseDebugMap(BinaryHolder &BinHolder, StringRef InputFile,
ArrayRef<std::string> Archs,
ArrayRef<std::string> DSYMSearchPaths, StringRef PrependPath,
- StringRef VariantSuffix, bool Verbose, bool InputIsYAML) {
+ StringRef VariantSuffix, bool Verbose, bool InputIsYAML,
+ const std::optional<StringSet<>> &ObjectFilter,
+ enum ObjectFilterType ObjectFilterType) {
if (InputIsYAML)
return DebugMap::parseYAMLDebugMap(BinHolder, InputFile, PrependPath,
Verbose);
MachODebugMapParser Parser(BinHolder, InputFile, Archs, DSYMSearchPaths,
- PrependPath, VariantSuffix, Verbose);
+ PrependPath, VariantSuffix, Verbose, ObjectFilter,
+ ObjectFilterType);
return Parser.parse();
}
diff --git a/llvm/tools/dsymutil/Options.td b/llvm/tools/dsymutil/Options.td
index 5334aa0a747b1..9b262660fe99a 100644
--- a/llvm/tools/dsymutil/Options.td
+++ b/llvm/tools/dsymutil/Options.td
@@ -229,6 +229,24 @@ def build_variant_suffix: Separate<["--", "-"], "build-variant-suffix">,
Group<grp_general>;
def: Joined<["--", "-"], "build-variant-suffix=">, Alias<build_variant_suffix>;
+def allow: Separate<["--", "-"], "allow">,
+ MetaVarName<"<path>">,
+ HelpText<"Only process debug map objects listed in the YAML file at <path>. "
+ "Only filters N_OSO entries. If `--oso-prepend-path` is specified, the path "
+ "prefix applies, i.e. paths in the file should exact match that of N_OSO "
+ "entries.">,
+ Group<grp_general>;
+def: Joined<["--", "-"], "allow=">, Alias<allow>;
+
+def disallow: Separate<["--", "-"], "disallow">,
+ MetaVarName<"<path>">,
+ HelpText<"Exclude debug map objects listed in the YAML file at <path>. "
+ "Only filters N_OSO entries. If `--oso-prepend-path` is specified, the path "
+ "prefix applies, i.e. paths in the file should exact match that of N_OSO "
+ "entries.">,
+ Group<grp_general>;
+def: Joined<["--", "-"], "disallow=">, Alias<disallow>;
+
def dsym_search_path: Separate<["-", "--"], "D">,
MetaVarName<"<path>">,
HelpText<"Specify a directory that contain dSYM files to search for.">,
diff --git a/llvm/tools/dsymutil/dsymutil.cpp b/llvm/tools/dsymutil/dsymutil.cpp
index ce55b7f6183e6..2f32a48b38804 100644
--- a/llvm/tools/dsymutil/dsymutil.cpp
+++ b/llvm/tools/dsymutil/dsymutil.cpp
@@ -23,6 +23,7 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSet.h"
#include "llvm/DebugInfo/DIContext.h"
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
#include "llvm/DebugInfo/DWARF/DWARFVerifier.h"
@@ -38,10 +39,12 @@
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/LLVMDriver.h"
+#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/ThreadPool.h"
#include "llvm/Support/WithColor.h"
+#include "llvm/Support/YAMLTraits.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/thread.h"
#include "llvm/TargetParser/Triple.h"
@@ -56,6 +59,33 @@ using namespace llvm::dsymutil;
using namespace object;
using namespace llvm::dwarf_linker;
+/// YAML structure for --allow / --disallow object list files.
+struct ObjectFileEntry {
+ std::string Filename;
+};
+
+struct ObjectFileList {
+ std::vector<ObjectFileEntry> Objects;
+};
+
+LLVM_YAML_IS_SEQUENCE_VECTOR(ObjectFileEntry)
+
+namespace llvm {
+namespace yaml {
+template <> struct MappingTraits<ObjectFileEntry> {
+ static void mapping(IO &IO, ObjectFileEntry &Entry) {
+ IO.mapRequired("filename", Entry.Filename);
+ }
+};
+
+template <> struct MappingTraits<ObjectFileList> {
+ static void mapping(IO &IO, ObjectFileList &List) {
+ IO.mapOptional("objects", List.Objects);
+ }
+};
+} // namespace yaml
+} // namespace llvm
+
namespace {
enum ID {
OPT_INVALID = 0, // This is not an option ID.
@@ -114,6 +144,8 @@ struct DsymutilOptions {
std::string OutputFile;
std::string Toolchain;
std::string ReproducerPath;
+ std::string AllowFile;
+ std::string DisallowFile;
std::vector<std::string> Archs;
std::vector<std::string> InputFiles;
unsigned NumThreads;
@@ -200,6 +232,17 @@ static Error verifyOptions(const DsymutilOptions &Options) {
"cannot combine --gen-reproducer and --use-reproducer.",
errc::invalid_argument);
+ if (Options.InputIsYAMLDebugMap &&
+ (!Options.AllowFile.empty() || !Options.DisallowFile.empty()))
+ return make_error<StringError>(
+ "-y and --allow/--disallow cannot be specified together",
+ errc::invalid_argument);
+
+ if (!Options.AllowFile.empty() && !Options.DisallowFile.empty())
+ return make_error<StringError>(
+ "--allow and --disallow cannot be specified together",
+ errc::invalid_argument);
+
return Error::success();
}
@@ -402,6 +445,12 @@ static Expected<DsymutilOptions> getOptions(opt::InputArgList &Args) {
for (auto *SearchPath : Args.filtered(OPT_dsym_search_path))
Options.LinkOpts.DSYMSearchPaths.push_back(SearchPath->getValue());
+ if (opt::Arg *AllowArg = Args.getLastArg(OPT_allow))
+ Options.AllowFile = AllowArg->getValue();
+
+ if (opt::Arg *DisallowArg = Args.getLastArg(OPT_disallow))
+ Options.DisallowFile = DisallowArg->getValue();
+
if (Error E = verifyOptions(Options))
return std::move(E);
return Options;
@@ -688,10 +737,63 @@ int dsymutil_main(int argc, char **argv, const llvm::ToolContext &) {
continue;
}
+ // Parse allow/disallow object list YAML files if specified.
+ std::optional<StringSet<>> ObjectFilter;
+ enum ObjectFilterType ObjectFilterType = Allow;
+
+ auto ParseAllowDisallowFile =
+ [&](const std::string &FilePath) -> Expected<StringSet<>> {
+ auto BufOrErr = MemoryBuffer::getFile(FilePath);
+ if (!BufOrErr)
+ return make_error<StringError>(
+ Twine("cannot open allow/disallow file '") + FilePath +
+ "': " + BufOrErr.getError().message(),
+ BufOrErr.getError());
+
+ StringSet<> Result;
+ StringRef Content = (*BufOrErr)->getBuffer();
+ if (!Content.trim().empty()) {
+ yaml::Input YAMLIn(Content);
+ ObjectFileList ObjList;
+ YAMLIn >> ObjList;
+ if (YAMLIn.error())
+ return make_error<StringError>(
+ Twine("cannot parse allow/disallow file '") + FilePath + "'",
+ YAMLIn.error());
+ for (const auto &Entry : ObjList.Objects) {
+ SmallString<80> Path(Options.LinkOpts.PrependPath);
+ sys::path::append(Path, Entry.Filename);
+ Result.insert(Path);
+ }
+ }
+ return Result;
+ };
+
+ if (!Options.AllowFile.empty()) {
+ auto AllowedOrErr = ParseAllowDisallowFile(Options.AllowFile);
+ if (!AllowedOrErr) {
+ WithColor::error() << toString(AllowedOrErr.takeError()) << '\n';
+ return EXIT_FAILURE;
+ }
+ ObjectFilter = std::move(*AllowedOrErr);
+ ObjectFilterType = Allow;
+ }
+
+ if (!Options.DisallowFile.empty()) {
+ auto DisallowedOrErr = ParseAllowDisallowFile(Options.DisallowFile);
+ if (!DisallowedOrErr) {
+ WithColor::error() << toString(DisallowedOrErr.takeError()) << '\n';
+ return EXIT_FAILURE;
+ }
+ ObjectFilter = std::move(*DisallowedOrErr);
+ ObjectFilterType = Disallow;
+ }
+
auto DebugMapPtrsOrErr = parseDebugMap(
BinHolder, InputFile, Options.Archs, Options.LinkOpts.DSYMSearchPaths,
Options.LinkOpts.PrependPath, Options.LinkOpts.BuildVariantSuffix,
- Options.LinkOpts.Verbose, Options.InputIsYAMLDebugMap);
+ Options.LinkOpts.Verbose, Options.InputIsYAMLDebugMap, ObjectFilter,
+ ObjectFilterType);
if (auto EC = DebugMapPtrsOrErr.getError()) {
WithColor::error() << "cannot parse the debug map for '" << InputFile
diff --git a/llvm/tools/dsymutil/dsymutil.h b/llvm/tools/dsymutil/dsymutil.h
index 7b97b8bcd3a25..af57fce159542 100644
--- a/llvm/tools/dsymutil/dsymutil.h
+++ b/llvm/tools/dsymutil/dsymutil.h
@@ -21,15 +21,19 @@
#include "LinkUtils.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSet.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/ErrorOr.h"
#include <memory>
+#include <optional>
#include <string>
#include <vector>
namespace llvm {
namespace dsymutil {
+enum ObjectFilterType { Allow, Disallow };
+
/// Extract the DebugMaps from the given file.
/// The file has to be a MachO object file. Multiple debug maps can be
/// returned when the file is universal (aka fat) binary.
@@ -37,7 +41,9 @@ ErrorOr<std::vector<std::unique_ptr<DebugMap>>>
parseDebugMap(BinaryHolder &BinHolder, StringRef InputFile,
ArrayRef<std::string> Archs,
ArrayRef<std::string> DSYMSearchPaths, StringRef PrependPath,
- StringRef VariantSuffix, bool Verbose, bool InputIsYAML);
+ StringRef VariantSuffix, bool Verbose, bool InputIsYAML,
+ const std::optional<StringSet<>> &ObjectFilter = std::nullopt,
+ ObjectFilterType ObjectFilterType = ObjectFilterType::Allow);
/// Dump the symbol table.
bool dumpStab(BinaryHolder &BinHolder, StringRef InputFile,
More information about the llvm-commits
mailing list