llvm.org GIT mirror llvm / 5a0743e
[dsymutil] Implement the BinaryHolder object and gain archive support. This object is meant to own the ObjectFiles and their underlying MemoryBuffer. It is basically the equivalent of an OwningBinary except that it efficiently handles Archives. It is optimized for efficiently providing mappings of members of the same archive when they are opened successively (which is standard in Darwin debug maps, objects from the same archive will be contiguous). Of course, the BinaryHolder will also be used by the DWARF linker once it is commited, but for now only the debug map parser uses it. With this change, you can run llvm-dsymutil on your Darwin debug build of clang and get a complete debug map for it. Differential Revision: http://reviews.llvm.org/D6690 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@225207 91177308-0d34-0410-b5e6-96231b3b80d8 Frederic Riss 5 years ago
8 changed file(s) with 266 addition(s) and 35 deletion(s). Raw diff Collapse all Expand all
1515 clang basic1-lto.o basic2-lto.o basic3-lto.o -o basic-lto.macho.x86_64 -Wl,-object_path_lto,$PWD/basic-lto.macho.x86_64.o -Wl,-dead_strip
1616 rm basic1-lto.o basic2-lto.o basic3-lto.o
1717
18 Archive compilation (after basic compilation):
19 ar -q libbasic.a basic2.macho.x86_64.o basic3.macho.x86_64.o
20 clang basic1.macho.x86_64.o -lbasic -o basic-archive.macho.x86_64 -Wl,-dead_strip -L.
1821 */
1922
2023 int foo(int);
0 RUN: llvm-dsymutil -v -parse-only -oso-prepend-path=%p %p/Inputs/basic.macho.x86_64 | FileCheck %s
11 RUN: llvm-dsymutil -v -parse-only -oso-prepend-path=%p %p/Inputs/basic-lto.macho.x86_64 | FileCheck %s --check-prefix=CHECK-LTO
2 RUN: llvm-dsymutil -v -parse-only -oso-prepend-path=%p %p/Inputs/basic-archive.macho.x86_64 | FileCheck %s --check-prefix=CHECK-ARCHIVE
23 RUN: llvm-dsymutil -v -parse-only %p/Inputs/basic.macho.x86_64 2>&1 | FileCheck %s --check-prefix=NOT-FOUND
34 RUN: not llvm-dsymutil -v -parse-only %p/Inputs/inexistant 2>&1 | FileCheck %s --check-prefix=NO-EXECUTABLE
5
6
47 Check that We can parse the debug map of the basic executable.
58
69 CHECK-NOT: error
3235 CHECK-LTO: 00000000000008ec => 0000000100001004 _val
3336 CHECK-LTO: END DEBUG MAP
3437
38 Check thet we correctly handle debug maps with archive members (including only
39 opening the archive once if mulitple of its members are used).
40
41 CHECK-ARCHIVE: trying to open {{.*}}basic-archive.macho.x86_64'
42 CHECK-ARCHIVE-NEXT: loaded file.
43 CHECK-ARCHIVE-NEXT: trying to open {{.*}}/Inputs/basic1.macho.x86_64.o'
44 CHECK-ARCHIVE-NEXT: loaded file.
45 CHECK-ARCHIVE-NEXT: trying to open {{.*}}/libbasic.a(basic2.macho.x86_64.o)'
46 CHECK-ARCHIVE-NEXT: opened new archive {{.*}}/libbasic.a'
47 CHECK-ARCHIVE-NEXT: found member in current archive.
48 CHECK-ARCHIVE-NEXT: trying to open {{.*}}/libbasic.a(basic3.macho.x86_64.o)'
49 CHECK-ARCHIVE-NEXT: found member in current archive.
50 CHECK-ARCHIVE: DEBUG MAP: object addr => executable addr symbol name
51 CHECK-ARCHIVE: /Inputs/basic1.macho.x86_64.o:
52 CHECK-ARCHIVE: 0000000000000000 => 0000000100000ea0 _main
53 CHECK-ARCHIVE: /Inputs/./libbasic.a(basic2.macho.x86_64.o):
54 CHECK-ARCHIVE: 0000000000000310 => 0000000100001000 _baz
55 CHECK-ARCHIVE: 0000000000000020 => 0000000100000ed0 _foo
56 CHECK-ARCHIVE: 0000000000000070 => 0000000100000f20 _inc
57 CHECK-ARCHIVE: 0000000000000560 => 0000000100001004 _private_int
58 CHECK-ARCHIVE: /Inputs/./libbasic.a(basic3.macho.x86_64.o):
59 CHECK-ARCHIVE: 0000000000000020 => 0000000100000f40 _bar
60 CHECK-ARCHIVE: 0000000000000070 => 0000000100000f90 _inc
61 CHECK-ARCHIVE: 0000000000000004 => 0000000100001008 _val
62 CHECK-ARCHIVE: END DEBUG MAP
63
3564 Check that we warn about missing object files (this presumes that the files aren't
3665 present in the machine's /Inputs/ folder, which should be a pretty safe bet).
3766
0 //===-- BinaryHolder.cpp --------------------------------------------------===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This program is a utility that aims to be a dropin replacement for
10 // Darwin's dsymutil.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #include "BinaryHolder.h"
15 #include "llvm/Support/raw_ostream.h"
16
17 namespace llvm {
18 namespace dsymutil {
19
20 ErrorOr
21 BinaryHolder::GetMemoryBufferForFile(StringRef Filename) {
22 if (Verbose)
23 outs() << "trying to open '" << Filename << "'\n";
24
25 // Try that first as it doesn't involve any filesystem access.
26 if (auto ErrOrArchiveMember = GetArchiveMemberBuffer(Filename))
27 return *ErrOrArchiveMember;
28
29 // If the name ends with a closing paren, there is a huge chance
30 // it is an archive member specification.
31 if (Filename.endswith(")"))
32 if (auto ErrOrArchiveMember = MapArchiveAndGetMemberBuffer(Filename))
33 return *ErrOrArchiveMember;
34
35 // Otherwise, just try opening a standard file. If this is an
36 // archive member specifiaction and any of the above didn't handle it
37 // (either because the archive is not there anymore, or because the
38 // archive doesn't contain the requested member), this will still
39 // provide a sensible error message.
40 auto ErrOrFile = MemoryBuffer::getFileOrSTDIN(Filename);
41 if (auto Err = ErrOrFile.getError())
42 return Err;
43
44 if (Verbose)
45 outs() << "\tloaded file.\n";
46 CurrentArchive.reset();
47 CurrentMemoryBuffer = std::move(ErrOrFile.get());
48 return CurrentMemoryBuffer->getMemBufferRef();
49 }
50
51 ErrorOr
52 BinaryHolder::GetArchiveMemberBuffer(StringRef Filename) {
53 if (!CurrentArchive)
54 return make_error_code(errc::no_such_file_or_directory);
55
56 StringRef CurArchiveName = CurrentArchive->getFileName();
57 if (!Filename.startswith(Twine(CurArchiveName, "(").str()))
58 return make_error_code(errc::no_such_file_or_directory);
59
60 // Remove the archive name and the parens around the archive member name.
61 Filename = Filename.substr(CurArchiveName.size() + 1).drop_back();
62
63 for (const auto &Child : CurrentArchive->children()) {
64 if (auto NameOrErr = Child.getName())
65 if (*NameOrErr == Filename) {
66 if (Verbose)
67 outs() << "\tfound member in current archive.\n";
68 return Child.getMemoryBufferRef();
69 }
70 }
71
72 return make_error_code(errc::no_such_file_or_directory);
73 }
74
75 ErrorOr
76 BinaryHolder::MapArchiveAndGetMemberBuffer(StringRef Filename) {
77 StringRef ArchiveFilename = Filename.substr(0, Filename.find('('));
78
79 auto ErrOrBuff = MemoryBuffer::getFileOrSTDIN(ArchiveFilename);
80 if (auto Err = ErrOrBuff.getError())
81 return Err;
82
83 if (Verbose)
84 outs() << "\topened new archive '" << ArchiveFilename << "'\n";
85 auto ErrOrArchive = object::Archive::create((*ErrOrBuff)->getMemBufferRef());
86 if (auto Err = ErrOrArchive.getError())
87 return Err;
88
89 CurrentArchive = std::move(*ErrOrArchive);
90 CurrentMemoryBuffer = std::move(*ErrOrBuff);
91
92 return GetArchiveMemberBuffer(Filename);
93 }
94
95 ErrorOr
96 BinaryHolder::GetObjectFile(StringRef Filename) {
97 auto ErrOrMemBufferRef = GetMemoryBufferForFile(Filename);
98 if (auto Err = ErrOrMemBufferRef.getError())
99 return Err;
100
101 auto ErrOrObjectFile =
102 object::ObjectFile::createObjectFile(*ErrOrMemBufferRef);
103 if (auto Err = ErrOrObjectFile.getError())
104 return Err;
105
106 CurrentObjectFile = std::move(*ErrOrObjectFile);
107 return *CurrentObjectFile;
108 }
109 }
110 }
0 //===-- BinaryHolder.h - Utility class for accessing binaries -------------===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This program is a utility that aims to be a dropin replacement for
10 // Darwin's dsymutil.
11 //
12 //===----------------------------------------------------------------------===//
13 #ifndef LLVM_TOOLS_DSYMUTIL_BINARYHOLDER_H
14 #define LLVM_TOOLS_DSYMUTIL_BINARYHOLDER_H
15
16 #include "llvm/Object/Archive.h"
17 #include "llvm/Object/Error.h"
18 #include "llvm/Object/ObjectFile.h"
19 #include "llvm/Support/Errc.h"
20 #include "llvm/Support/ErrorOr.h"
21
22 namespace llvm {
23 namespace dsymutil {
24
25 /// \brief The BinaryHolder class is responsible for creating and
26 /// owning ObjectFile objects and their underlying MemoryBuffer. This
27 /// is different from a simple OwningBinary in that it handles
28 /// accessing to archive members.
29 ///
30 /// As an optimization, this class will reuse an already mapped and
31 /// parsed Archive object if 2 successive requests target the same
32 /// archive file (Which is always the case in debug maps).
33 /// Currently it only owns one memory buffer at any given time,
34 /// meaning that a mapping request will invalidate the previous memory
35 /// mapping.
36 class BinaryHolder {
37 std::unique_ptr CurrentArchive;
38 std::unique_ptr CurrentMemoryBuffer;
39 std::unique_ptr CurrentObjectFile;
40 bool Verbose;
41
42 /// \brief Get the MemoryBufferRef for the file specification in \p
43 /// Filename from the current archive.
44 ///
45 /// This function performs no system calls, it just looks up a
46 /// potential match for the given \p Filename in the currently
47 /// mapped archive if there is one.
48 ErrorOr GetArchiveMemberBuffer(StringRef Filename);
49
50 /// \brief Interpret Filename as an archive member specification,
51 /// map the corresponding archive to memory and return the
52 /// MemoryBufferRef corresponding to the described member.
53 ErrorOr MapArchiveAndGetMemberBuffer(StringRef Filename);
54
55 /// \brief Return the MemoryBufferRef that holds the memory
56 /// mapping for the given \p Filename. This function will try to
57 /// parse archive member specifications of the form
58 /// /path/to/archive.a(member.o).
59 ///
60 /// The returned MemoryBufferRef points to a buffer owned by this
61 /// object. The buffer is valid until the next call to
62 /// GetMemoryBufferForFile() on this object.
63 ErrorOr GetMemoryBufferForFile(StringRef Filename);
64
65 public:
66 BinaryHolder(bool Verbose) : Verbose(Verbose) {}
67
68 /// \brief Get the ObjectFile designated by the \p Filename. This
69 /// might be an archive member specification of the form
70 /// /path/to/archive.a(member.o).
71 ///
72 /// Calling this function invalidates the previous mapping owned by
73 /// the BinaryHolder.
74 ErrorOr GetObjectFile(StringRef Filename);
75
76 /// \brief Wraps GetObjectFile() to return a derived ObjectFile type.
77 template
78 ErrorOr GetFileAs(StringRef Filename) {
79 auto ErrOrObjFile = GetObjectFile(Filename);
80 if (auto Err = ErrOrObjFile.getError())
81 return Err;
82 if (const auto *Derived = dyn_cast(CurrentObjectFile.get()))
83 return *Derived;
84 return make_error_code(object::object_error::invalid_file_type);
85 }
86
87 /// \brief Access the currently owned ObjectFile. As successfull
88 /// call to GetObjectFile() or GetFileAs() must have been performed
89 /// before calling this.
90 const object::ObjectFile &Get() {
91 assert(CurrentObjectFile);
92 return *CurrentObjectFile;
93 }
94
95 /// \brief Access to a derived version of the currently owned
96 /// ObjectFile. The conversion must be known to be valid.
97 template const ObjectFileType &GetAs() {
98 return cast(*CurrentObjectFile);
99 }
100 };
101 }
102 }
103 #endif
44
55 add_llvm_tool(llvm-dsymutil
66 dsymutil.cpp
7 BinaryHolder.cpp
78 DebugMap.cpp
89 DwarfLinker.cpp
910 MachODebugMapParser.cpp
66 //
77 //===----------------------------------------------------------------------===//
88
9 #include "BinaryHolder.h"
910 #include "DebugMap.h"
1011 #include "dsymutil.h"
1112 #include "llvm/Object/MachO.h"
1920
2021 class MachODebugMapParser {
2122 public:
22 MachODebugMapParser(StringRef BinaryPath, StringRef PathPrefix = "")
23 MachODebugMapParser(StringRef BinaryPath, StringRef PathPrefix = "",
24 bool Verbose = false)
2325 : BinaryPath(BinaryPath), PathPrefix(PathPrefix),
24 CurrentDebugMapObject(nullptr) {}
26 MainBinaryHolder(Verbose), CurrentObjectHolder(Verbose) {}
2527
2628 /// \brief Parses and returns the DebugMap of the input binary.
2729 /// \returns an error in case the provided BinaryPath doesn't exist
3234 std::string BinaryPath;
3335 std::string PathPrefix;
3436
35 /// OwningBinary constructed from the BinaryPath.
36 object::OwningBinary MainOwningBinary;
37 /// Owns the MemoryBuffer for the main binary.
38 BinaryHolder MainBinaryHolder;
3739 /// Map of the binary symbol addresses.
3840 StringMap MainBinarySymbolAddresses;
3941 StringRef MainBinaryStrings;
4042 /// The constructed DebugMap.
4143 std::unique_ptr Result;
4244
43 /// Handle to the currently processed object file.
44 object::OwningBinary CurrentObjectFile;
45 /// Owns the MemoryBuffer for the currently handled object file.
46 BinaryHolder CurrentObjectHolder;
4547 /// Map of the currently processed object file symbol addresses.
4648 StringMap CurrentObjectAddresses;
4749 /// Element of the debug map corresponfing to the current object file.
6567 static void Warning(const Twine &Msg) { errs() << "warning: " + Msg + "\n"; }
6668 }
6769
68 static ErrorOr>
69 createMachOBinary(StringRef File) {
70 auto MemBufOrErr = MemoryBuffer::getFile(File);
71 if (auto Error = MemBufOrErr.getError())
72 return Error;
73
74 MemoryBufferRef BufRef = (*MemBufOrErr)->getMemBufferRef();
75 auto MachOOrErr = ObjectFile::createMachOObjectFile(BufRef);
76 if (auto Error = MachOOrErr.getError())
77 return Error;
78
79 return OwningBinary(std::move(*MachOOrErr),
80 std::move(*MemBufOrErr));
81 }
82
8370 /// Reset the parser state coresponding to the current object
8471 /// file. This is to be called after an object file is finished
8572 /// processing.
8673 void MachODebugMapParser::resetParserState() {
87 CurrentObjectFile = OwningBinary();
8874 CurrentObjectAddresses.clear();
8975 CurrentDebugMapObject = nullptr;
9076 }
9884 SmallString<80> Path(PathPrefix);
9985 sys::path::append(Path, Filename);
10086
101 auto MachOOrError = createMachOBinary(Path);
87 auto MachOOrError = CurrentObjectHolder.GetFileAs(Path);
10288 if (auto Error = MachOOrError.getError()) {
10389 Warning(Twine("cannot open debug object \"") + Path.str() + "\": " +
10490 Error.message() + "\n");
10591 return;
10692 }
10793
108 CurrentObjectFile = std::move(*MachOOrError);
10994 loadCurrentObjectFileSymbols();
11095 CurrentDebugMapObject = &Result->addDebugMapObject(Path);
11196 }
11499 /// successful iterates over the STAB entries. The real parsing is
115100 /// done in handleStabSymbolTableEntry.
116101 ErrorOr> MachODebugMapParser::parse() {
117 auto MainBinaryOrError = createMachOBinary(BinaryPath);
118 if (auto Error = MainBinaryOrError.getError())
102 auto MainBinOrError = MainBinaryHolder.GetFileAs(BinaryPath);
103 if (auto Error = MainBinOrError.getError())
119104 return Error;
120105
121 MainOwningBinary = std::move(*MainBinaryOrError);
106 const MachOObjectFile &MainBinary = *MainBinOrError;
122107 loadMainBinarySymbols();
123108 Result = make_unique();
124 const auto &MainBinary = *MainOwningBinary.getBinary();
125109 MainBinaryStrings = MainBinary.getStringTableData();
126110 for (const SymbolRef &Symbol : MainBinary.symbols()) {
127111 const DataRefImpl &DRI = Symbol.getRawDataRefImpl();
189173 /// Load the current object file symbols into CurrentObjectAddresses.
190174 void MachODebugMapParser::loadCurrentObjectFileSymbols() {
191175 CurrentObjectAddresses.clear();
192 const auto &Binary = *CurrentObjectFile.getBinary();
193
194 for (auto Sym : Binary.symbols()) {
176
177 for (auto Sym : CurrentObjectHolder.Get().symbols()) {
195178 StringRef Name;
196179 uint64_t Addr;
197180 if (Sym.getAddress(Addr) || Addr == UnknownAddressOrSize ||
214197 /// Load the interesting main binary symbols' addresses into
215198 /// MainBinarySymbolAddresses.
216199 void MachODebugMapParser::loadMainBinarySymbols() {
217 const MachOObjectFile &Binary = *MainOwningBinary.getBinary();
218 section_iterator Section = Binary.section_end();
219 for (const auto &Sym : Binary.symbols()) {
200 const MachOObjectFile &MainBinary = MainBinaryHolder.GetAs();
201 section_iterator Section = MainBinary.section_end();
202 for (const auto &Sym : MainBinary.symbols()) {
220203 SymbolRef::Type Type;
221204 // Skip undefined and STAB entries.
222205 if (Sym.getType(Type) || (Type & SymbolRef::ST_Debug) ||
242225 llvm::ErrorOr> parseDebugMap(StringRef InputFile,
243226 StringRef PrependPath,
244227 bool Verbose) {
245 MachODebugMapParser Parser(InputFile, PrependPath);
228 MachODebugMapParser Parser(InputFile, PrependPath, Verbose);
246229 return Parser.parse();
247230 }
248231 }