-
Notifications
You must be signed in to change notification settings - Fork 15.4k
[llvm-symbolizer] Recognize AIX big archive #150401
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 46 commits
d98ed02
64639e1
f5a357e
305ef99
66d5d11
27b4f10
647f98e
629e7a5
8c71818
f0be9a8
bfa845e
9c14b38
f8aeb3e
0952fcf
6be8d1a
12dd6e5
68b886f
d0f0a1d
fe5a9c2
e2083eb
12bf16a
0595460
4d46767
315b98c
b37409b
30e4387
08f38ae
ca85990
844906c
74d4e23
183197a
c68b4d9
7407769
4da5ebd
b0f0705
86f2023
f034d90
c6d8b90
e4d6fed
f57d66a
c3acb24
136bde7
b59b5f7
8a2a05d
59f4b64
93e5a7c
af06657
b12e445
307fb74
d91dcd8
181ee67
fdcfdc0
2ad39b3
d16b8d4
0b06059
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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 AIX 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 AIX archives, the format ``archive.a(member.o):arch`` | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The docs here still refer to AIX archives specifically, yet the behaviour change is generic.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shared objects are normally stored in (and loaded from) archives on AIX. By convention, the same (big format) archive contains both 32-bit and 64-bit objects This behaviour is AIX specific, hence the documentation is more specific to AIX
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Behavior such as having same object name which vary in architecture getting added to archive is specific to AIX |
||
| 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 | ||
midhuncodes7 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| $ 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 | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -26,6 +26,7 @@ | |||||
| #include <map> | ||||||
| #include <memory> | ||||||
| #include <string> | ||||||
| #include <unordered_map> | ||||||
| #include <utility> | ||||||
| #include <vector> | ||||||
|
|
||||||
|
|
@@ -196,11 +197,18 @@ class LLVMSymbolizer { | |||||
| 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 +224,41 @@ class LLVMSymbolizer { | |||||
| /// 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 | ||||||
|
||||||
| /// Store the archive path for the object file | |
| /// Store the archive path for the object file. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
corrected
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please review the section on map types in the LLVM programmer's manual.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Used DenseMap instead
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this comment up-to-date?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updated the comment
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Exactly how is this comment aiding readability? What does it add that the function name itself doesn't add?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed comment
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use std::optional for optional types, not pointers.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Used std::optional
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as above re. comment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed comment
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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,158 @@ 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 = (Twine(ArchivePath) + "(" + MemberName + ")").str(); | ||
|
||
| } else { | ||
| FullDbgObjKey = DbgObj->getFileName().str(); | ||
| } | ||
| BinaryForPath.find(FullDbgObjKey) | ||
| ->second.pushEvictor( | ||
| [this, I = Pair.first]() { ObjectPairForPathArch.erase(I); }); | ||
| return Res; | ||
| } | ||
|
|
||
| Expected<ObjectFile *> | ||
| LLVMSymbolizer::getOrCreateObject(const std::string &Path, | ||
| const std::string &ArchName) { | ||
| Binary *Bin; | ||
| auto Pair = BinaryForPath.emplace(Path, OwningBinary<Binary>()); | ||
| Expected<object::Binary *> | ||
| LLVMSymbolizer::loadOrGetBinary(const std::string &OpenPath, | ||
| const std::string *FullPathKeyOpt) { | ||
| // If no separate cache key is provided, use the open path itself. | ||
|
||
| const std::string &FullPathKey = FullPathKeyOpt ? *FullPathKeyOpt : OpenPath; | ||
| auto Pair = BinaryForPath.emplace(FullPathKey, 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(); | ||
| return Pair.first->second->getBinary(); | ||
| } | ||
|
|
||
| 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(); | ||
| Expected<OwningBinary<Binary>> BinOrErr = createBinary(OpenPath); | ||
| if (!BinOrErr) { | ||
|
||
| return BinOrErr.takeError(); | ||
| } | ||
|
|
||
| if (!Bin) | ||
| return static_cast<ObjectFile *>(nullptr); | ||
| 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(); | ||
| } | ||
|
|
||
| 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(); | ||
| 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) { | ||
| std::string FullPathKeyStr = FullPath.str(); | ||
| Expected<object::Binary *> BinOrErr = | ||
| loadOrGetBinary(ArchivePath.str(), &FullPathKeyStr); | ||
| 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, | ||
jh7370 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| "'%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) | ||
| continue; | ||
jh7370 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| if (*NameOrErr == MemberName) { | ||
| Expected<std::unique_ptr<object::Binary>> MemberOrErr = | ||
| Child.getAsBinary(); | ||
| if (!MemberOrErr) | ||
| continue; | ||
jh7370 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| 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; | ||
| } | ||
| } | ||
| 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; | ||
| } | ||
| 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) { | ||
jh7370 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| // 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); | ||
| StringRef FullPath = Path; | ||
jh7370 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| return getOrCreateObjectFromArchive(ArchivePath, MemberName, ArchName, | ||
| FullPath); | ||
| } | ||
| } | ||
|
|
||
| Expected<object::Binary *> BinOrErr = loadOrGetBinary(Path); | ||
| if (!BinOrErr) | ||
| return BinOrErr.takeError(); | ||
| object::Binary *Bin = *BinOrErr; | ||
|
|
||
| if (MachOUniversalBinary *UB = dyn_cast_or_null<MachOUniversalBinary>(Bin)) { | ||
| 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); | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.