[llvm-symbolizer] Recognize and symbolize archive members (#150401)

This PR adds support for selecting specific archive members in
llvm-symbolizer using the `archive.a(member.o)` syntax, with
architecture-aware member selection.

  **Key features:**
1. **Archive member selection syntax**: Specify archive members using
`archive.a(member.o)` format
2. **Architecture selection via `--default-arch` flag**: Select the
appropriate member when multiple members have the same name but
different architectures
3. **Architecture selection via `:arch` suffix**: Alternative syntax
`archive.a(member.o):arch` for specifying architecture

This functionality is primarily designed for AIX big archives, which can
contain multiple members with the same name but different architectures
(32-bit and 64-bit). However, the implementation works with all archive
formats (GNU, BSD, Darwin, big archive) and handles same-named members
created with llvm-ar q.

---------

Co-authored-by: Midhunesh <midhuensh.p@ibm.com>
This commit is contained in:
Midhunesh
2025-12-15 18:55:36 +05:30
committed by GitHub
parent 6e01ea4bab
commit ee5b9cd59d
6 changed files with 460 additions and 55 deletions

View File

@@ -535,16 +535,20 @@ MACH-O SPECIFIC OPTIONS
.. option:: --default-arch <arch>
If a binary contains object files for multiple architectures (e.g. it is a
Mach-O universal binary), symbolize the object file for a given architecture.
You can also specify the architecture by writing ``binary_name:arch_name`` in
the input (see example below). If the architecture is not specified in either
way, the address will not be symbolized. Defaults to empty string.
Mach-O universal binary or an archive with architecture variants),
symbolize the object file for a given architecture. You can also specify
the architecture by writing ``binary_name:arch_name`` in the input (see
example below). For archives, the format ``archive.a(member.o):arch``
is also supported. If the architecture is not specified,
the address will not be symbolized. Defaults to empty string.
.. code-block:: console
$ cat addr.txt
/tmp/mach_universal_binary:i386 0x1f84
/tmp/mach_universal_binary:x86_64 0x100000f24
/tmp/archive.a(member.o):ppc 0x1000
/tmp/archive.a(member.o):ppc64 0x2000
$ llvm-symbolizer < addr.txt
_main
@@ -553,6 +557,12 @@ MACH-O SPECIFIC OPTIONS
_main
/tmp/source_x86_64.cc:8
_foo
/tmp/source_ppc.cc:12
_foo
/tmp/source_ppc64.cc:12
.. option:: --dsym-hint <path/to/file.dSYM>
If the debug info for a binary isn't present in the default location, look for

View File

@@ -13,6 +13,7 @@
#ifndef LLVM_DEBUGINFO_SYMBOLIZE_SYMBOLIZE_H
#define LLVM_DEBUGINFO_SYMBOLIZE_SYMBOLIZE_H
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/ilist_node.h"
#include "llvm/ADT/simple_ilist.h"
@@ -25,6 +26,7 @@
#include <cstdint>
#include <map>
#include <memory>
#include <optional>
#include <string>
#include <utility>
#include <vector>
@@ -196,11 +198,18 @@ private:
Expected<ObjectPair> getOrCreateObjectPair(const std::string &Path,
const std::string &ArchName);
/// Return a pointer to object file at specified path, for a specified
/// architecture (e.g. if path refers to a Mach-O universal binary, only one
/// object file from it will be returned).
Expected<ObjectFile *> getOrCreateObject(const std::string &Path,
const std::string &ArchName);
/// Return a pointer to the object file with the specified name, for a
/// specified architecture (e.g. if path refers to a Mach-O universal
/// binary, only one object file from it will be returned).
Expected<ObjectFile *> getOrCreateObject(const std::string &InputPath,
const std::string &DefaultArchName);
/// Return a pointer to the object file with the specified name, for a
/// specified architecture that is present inside an archive file.
Expected<ObjectFile *> getOrCreateObjectFromArchive(StringRef ArchivePath,
StringRef MemberName,
StringRef ArchName,
StringRef FullPath);
/// Update the LRU cache order when a binary is accessed.
void recordAccess(CachedBinary &Bin);
@@ -216,15 +225,39 @@ private:
/// Contains parsed binary for each path, or parsing error.
std::map<std::string, CachedBinary, std::less<>> BinaryForPath;
/// Store the archive path for the object file.
DenseMap<const object::ObjectFile *, std::string> ObjectToArchivePath;
/// A list of cached binaries in LRU order.
simple_ilist<CachedBinary> LRUBinaries;
/// Sum of the sizes of the cached binaries.
size_t CacheSize = 0;
/// Parsed object file for path/architecture pair, where "path" refers
/// to Mach-O universal binary.
std::map<std::pair<std::string, std::string>, std::unique_ptr<ObjectFile>>
ObjectForUBPathAndArch;
struct ContainerCacheKey {
std::string Path;
std::string MemberName;
std::string ArchName;
// Required for map comparison.
bool operator<(const ContainerCacheKey &Other) const {
return std::tie(Path, MemberName, ArchName) <
std::tie(Other.Path, Other.MemberName, Other.ArchName);
}
};
/// Parsed object file for each path/member/architecture triple.
/// Used to cache objects extracted from containers (e.g., Mach-O
/// universal binaries, archives).
std::map<ContainerCacheKey, std::unique_ptr<ObjectFile>> ObjectFileCache;
Expected<object::Binary *>
loadOrGetBinary(const std::string &ArchivePathKey,
std::optional<StringRef> FullPathKey = std::nullopt);
Expected<ObjectFile *> findOrCacheObject(
const ContainerCacheKey &Key,
llvm::function_ref<Expected<std::unique_ptr<ObjectFile>>()> Loader,
const std::string &PathForBinaryCache);
Options Opts;

View File

@@ -21,6 +21,7 @@
#include "llvm/DebugInfo/PDB/PDBContext.h"
#include "llvm/DebugInfo/Symbolize/SymbolizableObjectFile.h"
#include "llvm/Demangle/Demangle.h"
#include "llvm/Object/Archive.h"
#include "llvm/Object/BuildID.h"
#include "llvm/Object/COFF.h"
#include "llvm/Object/ELFObjectFile.h"
@@ -285,7 +286,7 @@ LLVMSymbolizer::findSymbol(ArrayRef<uint8_t> BuildID, StringRef Symbol,
}
void LLVMSymbolizer::flush() {
ObjectForUBPathAndArch.clear();
ObjectFileCache.clear();
LRUBinaries.clear();
CacheSize = 0;
BinaryForPath.clear();
@@ -557,57 +558,164 @@ LLVMSymbolizer::getOrCreateObjectPair(const std::string &Path,
if (!DbgObj)
DbgObj = Obj;
ObjectPair Res = std::make_pair(Obj, DbgObj);
std::string DbgObjPath = DbgObj->getFileName().str();
auto Pair =
ObjectPairForPathArch.emplace(std::make_pair(Path, ArchName), Res);
BinaryForPath.find(DbgObjPath)->second.pushEvictor([this, I = Pair.first]() {
ObjectPairForPathArch.erase(I);
});
std::string FullDbgObjKey;
auto It = ObjectToArchivePath.find(DbgObj);
if (It != ObjectToArchivePath.end()) {
StringRef ArchivePath = It->second;
StringRef MemberName = sys::path::filename(DbgObj->getFileName());
FullDbgObjKey = (ArchivePath + "(" + MemberName + ")").str();
} else {
FullDbgObjKey = DbgObj->getFileName().str();
}
BinaryForPath.find(FullDbgObjKey)
->second.pushEvictor(
[this, I = Pair.first]() { ObjectPairForPathArch.erase(I); });
return Res;
}
Expected<object::Binary *>
LLVMSymbolizer::loadOrGetBinary(const std::string &ArchivePathKey,
std::optional<StringRef> FullPathKey) {
// If no separate cache key is provided, use the archive path itself.
std::string FullPathKeyStr =
FullPathKey ? FullPathKey->str() : ArchivePathKey;
auto Pair = BinaryForPath.emplace(FullPathKeyStr, OwningBinary<Binary>());
if (!Pair.second) {
recordAccess(Pair.first->second);
return Pair.first->second->getBinary();
}
Expected<OwningBinary<Binary>> BinOrErr = createBinary(ArchivePathKey);
if (!BinOrErr)
return BinOrErr.takeError();
CachedBinary &CachedBin = Pair.first->second;
CachedBin = std::move(*BinOrErr);
CachedBin.pushEvictor([this, I = Pair.first]() { BinaryForPath.erase(I); });
LRUBinaries.push_back(CachedBin);
CacheSize += CachedBin.size();
return CachedBin->getBinary();
}
Expected<ObjectFile *> LLVMSymbolizer::findOrCacheObject(
const ContainerCacheKey &Key,
llvm::function_ref<Expected<std::unique_ptr<ObjectFile>>()> Loader,
const std::string &PathForBinaryCache) {
auto It = ObjectFileCache.find(Key);
if (It != ObjectFileCache.end())
return It->second.get();
Expected<std::unique_ptr<ObjectFile>> ObjOrErr = Loader();
if (!ObjOrErr) {
ObjectFileCache.emplace(Key, std::unique_ptr<ObjectFile>());
return ObjOrErr.takeError();
}
ObjectFile *Res = ObjOrErr->get();
auto NewEntry = ObjectFileCache.emplace(Key, std::move(*ObjOrErr));
auto CacheIter = BinaryForPath.find(PathForBinaryCache);
if (CacheIter != BinaryForPath.end())
CacheIter->second.pushEvictor(
[this, Iter = NewEntry.first]() { ObjectFileCache.erase(Iter); });
return Res;
}
Expected<ObjectFile *> LLVMSymbolizer::getOrCreateObjectFromArchive(
StringRef ArchivePath, StringRef MemberName, StringRef ArchName,
StringRef FullPath) {
Expected<object::Binary *> BinOrErr =
loadOrGetBinary(ArchivePath.str(), FullPath);
if (!BinOrErr)
return BinOrErr.takeError();
object::Binary *Bin = *BinOrErr;
object::Archive *Archive = dyn_cast_if_present<object::Archive>(Bin);
if (!Archive)
return createStringError(std::errc::invalid_argument,
"'%s' is not a valid archive",
ArchivePath.str().c_str());
Error Err = Error::success();
for (auto &Child : Archive->children(Err, /*SkipInternal=*/true)) {
Expected<StringRef> NameOrErr = Child.getName();
if (!NameOrErr) {
// TODO: Report this as a warning to the client. Consider adding a
// callback mechanism to report warning-level issues.
consumeError(NameOrErr.takeError());
continue;
}
if (*NameOrErr == MemberName) {
Expected<std::unique_ptr<object::Binary>> MemberOrErr =
Child.getAsBinary();
if (!MemberOrErr) {
// TODO: Report this as a warning to the client. Consider adding a
// callback mechanism to report warning-level issues.
consumeError(MemberOrErr.takeError());
continue;
}
std::unique_ptr<object::Binary> Binary = std::move(*MemberOrErr);
if (auto *Obj = dyn_cast<object::ObjectFile>(Binary.get())) {
ObjectToArchivePath[Obj] = ArchivePath.str();
Triple::ArchType ObjArch = Obj->makeTriple().getArch();
Triple RequestedTriple;
RequestedTriple.setArch(Triple::getArchTypeForLLVMName(ArchName));
if (ObjArch != RequestedTriple.getArch())
continue;
ContainerCacheKey CacheKey{ArchivePath.str(), MemberName.str(),
ArchName.str()};
Expected<ObjectFile *> Res = findOrCacheObject(
CacheKey,
[O = std::unique_ptr<ObjectFile>(
Obj)]() mutable -> Expected<std::unique_ptr<ObjectFile>> {
return std::move(O);
},
ArchivePath.str());
Binary.release();
return Res;
}
}
}
if (Err)
return std::move(Err);
return createStringError(std::errc::invalid_argument,
"no matching member '%s' with arch '%s' in '%s'",
MemberName.str().c_str(), ArchName.str().c_str(),
ArchivePath.str().c_str());
}
Expected<ObjectFile *>
LLVMSymbolizer::getOrCreateObject(const std::string &Path,
const std::string &ArchName) {
Binary *Bin;
auto Pair = BinaryForPath.emplace(Path, OwningBinary<Binary>());
if (!Pair.second) {
Bin = Pair.first->second->getBinary();
recordAccess(Pair.first->second);
} else {
Expected<OwningBinary<Binary>> BinOrErr = createBinary(Path);
if (!BinOrErr)
return BinOrErr.takeError();
CachedBinary &CachedBin = Pair.first->second;
CachedBin = std::move(BinOrErr.get());
CachedBin.pushEvictor([this, I = Pair.first]() { BinaryForPath.erase(I); });
LRUBinaries.push_back(CachedBin);
CacheSize += CachedBin.size();
Bin = CachedBin->getBinary();
// First check for archive(member) format - more efficient to check closing
// paren first.
if (!Path.empty() && Path.back() == ')') {
size_t OpenParen = Path.rfind('(', Path.size() - 1);
if (OpenParen != std::string::npos) {
StringRef ArchivePath = StringRef(Path).substr(0, OpenParen);
StringRef MemberName =
StringRef(Path).substr(OpenParen + 1, Path.size() - OpenParen - 2);
return getOrCreateObjectFromArchive(ArchivePath, MemberName, ArchName,
Path);
}
}
if (!Bin)
return static_cast<ObjectFile *>(nullptr);
Expected<object::Binary *> BinOrErr = loadOrGetBinary(Path);
if (!BinOrErr)
return BinOrErr.takeError();
object::Binary *Bin = *BinOrErr;
if (MachOUniversalBinary *UB = dyn_cast_or_null<MachOUniversalBinary>(Bin)) {
auto I = ObjectForUBPathAndArch.find(std::make_pair(Path, ArchName));
if (I != ObjectForUBPathAndArch.end())
return I->second.get();
Expected<std::unique_ptr<ObjectFile>> ObjOrErr =
UB->getMachOObjectForArch(ArchName);
if (!ObjOrErr) {
ObjectForUBPathAndArch.emplace(std::make_pair(Path, ArchName),
std::unique_ptr<ObjectFile>());
return ObjOrErr.takeError();
}
ObjectFile *Res = ObjOrErr->get();
auto Pair = ObjectForUBPathAndArch.emplace(std::make_pair(Path, ArchName),
std::move(ObjOrErr.get()));
BinaryForPath.find(Path)->second.pushEvictor(
[this, Iter = Pair.first]() { ObjectForUBPathAndArch.erase(Iter); });
return Res;
ContainerCacheKey CacheKey{Path, "", ArchName};
return findOrCacheObject(
CacheKey,
[UB, ArchName]() -> Expected<std::unique_ptr<ObjectFile>> {
return UB->getMachOObjectForArch(ArchName);
},
Path);
}
if (Bin->isObject()) {
return cast<ObjectFile>(Bin);

View File

@@ -0,0 +1,129 @@
## Test big archive recognition with same-named members (XCOFF format).
## Big archives can contain multiple members with the same name but different
## architectures. This test verifies llvm-symbolizer can disambiguate using
## architecture specification.
# RUN: rm -rf %t.dir && mkdir %t.dir && cd %t.dir
# RUN: yaml2obj -DSYMBOL=foo32 --docnum=1 %s -o 32.o
# RUN: yaml2obj -DSYMBOL=foo64 --docnum=2 %s -o 64.o
# RUN: yaml2obj -DSYMBOL=foo1 --docnum=2 %s -o 1.o
# RUN: yaml2obj -DSYMBOL=foo2 --docnum=2 %s -o 2.o
## Create big archive with unique member names.
# RUN: llvm-ar --format=bigarchive %if system-aix %{-X64%} crv archive.a 1.o 2.o
## Create big archive with duplicate member names (64-bit first, 32-bit second).
# RUN: cp 64.o test.o
# RUN: llvm-ar --format=bigarchive %if system-aix %{-X64%} crv archive.a test.o
# RUN: cp 32.o test.o
# RUN: llvm-ar --format=bigarchive %if system-aix %{-X32 rv%} %else %{qv%} archive.a test.o
## Test symbolization with unique member names.
# RUN: llvm-symbolizer --default-arch=ppc64 --obj="archive.a(1.o)" 0x0 | FileCheck %s --check-prefix=CHECK-1
# RUN: llvm-symbolizer --obj="archive.a(1.o):ppc64" 0x0 | FileCheck %s --check-prefix=CHECK-1
# RUN: llvm-symbolizer --default-arch=ppc64 --obj="archive.a(2.o)" 0x0 | FileCheck %s --check-prefix=CHECK-2
# RUN: llvm-symbolizer --obj="archive.a(2.o):ppc64" 0x0 | FileCheck %s --check-prefix=CHECK-2
# CHECK-1: foo1
# CHECK-2: foo2
## Test 64-bit member (first in archive).
# RUN: llvm-symbolizer --default-arch=ppc64 --obj="archive.a(test.o)" 0x0 | FileCheck %s --check-prefix=CHECK-64
# RUN: llvm-symbolizer --obj="archive.a(test.o):ppc64" 0x0 | FileCheck %s --check-prefix=CHECK-64
# CHECK-64: foo64
## Test 32-bit member (second in archive).
# RUN: llvm-symbolizer --default-arch=ppc --obj="archive.a(test.o)" 0x0 | FileCheck %s --check-prefix=CHECK-32
# RUN: llvm-symbolizer --obj="archive.a(test.o):ppc" 0x0 | FileCheck %s --check-prefix=CHECK-32
# CHECK-32: foo32
## Test error: no matching architecture.
# RUN: not llvm-symbolizer --default-arch=x86_64 --obj="archive.a(test.o)" 0x1000 2>&1 | FileCheck %s --check-prefix=CHECK-NOARCH
# CHECK-NOARCH: error: 'archive.a(test.o)': no matching member 'test.o' with arch 'x86_64' in 'archive.a'
## Test error: no architecture specified.
# RUN: not llvm-symbolizer --obj="archive.a(test.o)" 0x1000 2>&1 | FileCheck %s --check-prefix=CHECK-NOARCHSPEC
# CHECK-NOARCHSPEC: error: 'archive.a(test.o)': no matching member 'test.o' with arch '' in 'archive.a'
## Test error: nonexistent member.
# RUN: not llvm-symbolizer --default-arch=ppc --obj="archive.a(nonexistent.o)" 0x1000 2>&1 | FileCheck %s --check-prefix=CHECK-ERROR
# CHECK-ERROR: error: 'archive.a(nonexistent.o)': no matching member 'nonexistent.o' with arch 'ppc' in 'archive.a'
## Test error: not an archive.
# RUN: not llvm-symbolizer --obj="test.o(test.o)" 0x1000 2>&1 | FileCheck %s --check-prefix=CHECK-NOTARCHIVE
# CHECK-NOTARCHIVE: error: 'test.o(test.o)': 'test.o' is not a valid archive
## Test error: empty member name.
# RUN: not llvm-symbolizer --obj="archive.a():ppc64" 0x1000 2>&1 | FileCheck %s --check-prefix=CHECK-NONAME
# CHECK-NONAME: error: 'archive.a():ppc64': no matching member '' with arch 'ppc64' in 'archive.a'
## 32-bit XCOFF object.
--- !XCOFF
FileHeader:
MagicNumber: 0x1DF
Sections:
- Name: .text
Flags: [ STYP_TEXT ]
SectionData: 4E800020
Symbols:
- Name: .file
Section: N_DEBUG
StorageClass: C_FILE
NumberOfAuxEntries: 1
AuxEntries:
- Type: AUX_FILE
FileNameOrString: foo.c
FileStringType: XFT_FN
- Name: .[[SYMBOL]]
Section: .text
StorageClass: C_EXT
NumberOfAuxEntries: 1
AuxEntries:
- Type: AUX_CSECT
SymbolType: XTY_LD
StorageMappingClass: XMC_PR
- Name: [[SYMBOL]]
Section: .text
StorageClass: C_EXT
NumberOfAuxEntries: 1
AuxEntries:
- Type: AUX_CSECT
SymbolType: XTY_SD
StorageMappingClass: XMC_PR
## 64-bit XCOFF object.
--- !XCOFF
FileHeader:
MagicNumber: 0x1F7
Sections:
- Name: .text
Flags: [ STYP_TEXT ]
SectionData: 4E800020
Symbols:
- Name: .file
Section: N_DEBUG
StorageClass: C_FILE
NumberOfAuxEntries: 1
AuxEntries:
- Type: AUX_FILE
FileNameOrString: foo.c
FileStringType: XFT_FN
- Name: .[[SYMBOL]]
Section: .text
StorageClass: C_EXT
NumberOfAuxEntries: 1
AuxEntries:
- Type: AUX_CSECT
SymbolType: XTY_LD
StorageMappingClass: XMC_PR
- Name: [[SYMBOL]]
Section: .text
StorageClass: C_EXT
NumberOfAuxEntries: 1
AuxEntries:
- Type: AUX_CSECT
SymbolType: XTY_SD
StorageMappingClass: XMC_PR

View File

@@ -0,0 +1,126 @@
## Test archive member recognition (GNU archive format).
# RUN: rm -rf %t.dir && mkdir %t.dir && cd %t.dir
# RUN: yaml2obj -DSYMBOL=foo32 --docnum=1 %s -o 32.o
# RUN: yaml2obj -DSYMBOL=foo64 --docnum=2 %s -o 64.o
# RUN: yaml2obj -DSYMBOL=foo1 --docnum=2 %s -o 1.o
# RUN: yaml2obj -DSYMBOL=foo2 --docnum=2 %s -o 2.o
## Create archive with unique member names.
# RUN: llvm-ar --format=gnu crv archive.a 1.o 2.o
## Create archive with duplicate member names (64-bit first, 32-bit second).
# RUN: cp 64.o test.o
# RUN: llvm-ar --format=gnu crv archive.a test.o
# RUN: cp 32.o test.o
# RUN: llvm-ar --format=gnu qv archive.a test.o
## Test symbolization with unique member names.
# RUN: llvm-symbolizer --default-arch=ppc64 --obj="archive.a(1.o)" 0x0 | FileCheck %s --check-prefix=CHECK-1
# RUN: llvm-symbolizer --obj="archive.a(1.o):ppc64" 0x0 | FileCheck %s --check-prefix=CHECK-1
# RUN: llvm-symbolizer --default-arch=ppc64 --obj="archive.a(2.o)" 0x0 | FileCheck %s --check-prefix=CHECK-2
# RUN: llvm-symbolizer --obj="archive.a(2.o):ppc64" 0x0 | FileCheck %s --check-prefix=CHECK-2
# CHECK-1: foo1
# CHECK-2: foo2
## Test 64-bit member (first in archive).
# RUN: llvm-symbolizer --default-arch=ppc64 --obj="archive.a(test.o)" 0x0 | FileCheck %s --check-prefix=CHECK-64
# RUN: llvm-symbolizer --obj="archive.a(test.o):ppc64" 0x0 | FileCheck %s --check-prefix=CHECK-64
# CHECK-64: foo64
## Test 32-bit member (second in archive).
# RUN: llvm-symbolizer --default-arch=ppc --obj="archive.a(test.o)" 0x0 | FileCheck %s --check-prefix=CHECK-32
# RUN: llvm-symbolizer --obj="archive.a(test.o):ppc" 0x0 | FileCheck %s --check-prefix=CHECK-32
# CHECK-32: foo32
## Test error: no matching architecture.
# RUN: not llvm-symbolizer --default-arch=x86_64 --obj="archive.a(test.o)" 0x1000 2>&1 | FileCheck %s --check-prefix=CHECK-NOARCH
# CHECK-NOARCH: error: 'archive.a(test.o)': no matching member 'test.o' with arch 'x86_64' in 'archive.a'
## Test error: no architecture specified.
# RUN: not llvm-symbolizer --obj="archive.a(test.o)" 0x1000 2>&1 | FileCheck %s --check-prefix=CHECK-NOARCHSPEC
# CHECK-NOARCHSPEC: error: 'archive.a(test.o)': no matching member 'test.o' with arch '' in 'archive.a'
## Test error: nonexistent member.
# RUN: not llvm-symbolizer --default-arch=ppc64 --obj="archive.a(nonexistent.o)" 0x1000 2>&1 | FileCheck %s --check-prefix=CHECK-ERROR
# CHECK-ERROR: error: 'archive.a(nonexistent.o)': no matching member 'nonexistent.o' with arch 'ppc64' in 'archive.a'
## Test error: not an archive.
# RUN: not llvm-symbolizer --obj="1.o(1.o)" 0x1000 2>&1 | FileCheck %s --check-prefix=CHECK-NOTARCHIVE
# CHECK-NOTARCHIVE: error: '1.o(1.o)': '1.o' is not a valid archive
## Test error: empty member name.
# RUN: not llvm-symbolizer --obj="archive.a():ppc64" 0x1000 2>&1 | FileCheck %s --check-prefix=CHECK-NONAME
# CHECK-NONAME: error: 'archive.a():ppc64': no matching member '' with arch 'ppc64' in 'archive.a'
## 32-bit XCOFF object.
--- !XCOFF
FileHeader:
MagicNumber: 0x1DF
Sections:
- Name: .text
Flags: [ STYP_TEXT ]
SectionData: 4E800020
Symbols:
- Name: .file
Section: N_DEBUG
StorageClass: C_FILE
NumberOfAuxEntries: 1
AuxEntries:
- Type: AUX_FILE
FileNameOrString: foo.c
FileStringType: XFT_FN
- Name: .[[SYMBOL]]
Section: .text
StorageClass: C_EXT
NumberOfAuxEntries: 1
AuxEntries:
- Type: AUX_CSECT
SymbolType: XTY_LD
StorageMappingClass: XMC_PR
- Name: [[SYMBOL]]
Section: .text
StorageClass: C_EXT
NumberOfAuxEntries: 1
AuxEntries:
- Type: AUX_CSECT
SymbolType: XTY_SD
StorageMappingClass: XMC_PR
## 64-bit XCOFF object.
--- !XCOFF
FileHeader:
MagicNumber: 0x1F7
Sections:
- Name: .text
Flags: [ STYP_TEXT ]
SectionData: 4E800020
Symbols:
- Name: .file
Section: N_DEBUG
StorageClass: C_FILE
NumberOfAuxEntries: 1
AuxEntries:
- Type: AUX_FILE
FileNameOrString: foo.c
FileStringType: XFT_FN
- Name: .[[SYMBOL]]
Section: .text
StorageClass: C_EXT
NumberOfAuxEntries: 1
AuxEntries:
- Type: AUX_CSECT
SymbolType: XTY_LD
StorageMappingClass: XMC_PR
- Name: [[SYMBOL]]
Section: .text
StorageClass: C_EXT
NumberOfAuxEntries: 1
AuxEntries:
- Type: AUX_CSECT
SymbolType: XTY_SD
StorageMappingClass: XMC_PR

View File

@@ -31,8 +31,7 @@ def color_EQ : Joined<["--"], "color=">, HelpText<"Whether to use color when sym
defm debug_file_directory : Eq<"debug-file-directory", "Path to directory where to look for debug files">, MetaVarName<"<dir>">;
defm debuginfod : B<"debuginfod", "Use debuginfod to find debug binaries", "Don't use debuginfod to find debug binaries">;
defm default_arch
: Eq<"default-arch", "Default architecture (for multi-arch objects)">,
Group<grp_mach_o>;
: Eq<"default-arch", "Default architecture for multi-arch containers (e.g. Mach-O objects or AIX archives)">;
defm demangle : B<"demangle", "Demangle function names", "Don't demangle function names">;
def disable_gsym : F<"disable-gsym", "Don't consider using GSYM files for symbolication">, Group<grp_gsym>;
def filter_markup : Flag<["--"], "filter-markup">, HelpText<"Filter symbolizer markup from stdin.">;