]>
Commit | Line | Data |
---|---|---|
487cf647 FG |
1 | // Derived from code in LLVM, which is: |
2 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
3 | // See https://llvm.org/LICENSE.txt for license information. | |
4 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
5 | ||
6 | // Derived from: | |
7 | // * https://github.com/llvm/llvm-project/blob/8ef3e895ad8ab1724e2b87cabad1dacdc7a397a3/llvm/include/llvm/Object/ArchiveWriter.h | |
8 | // * https://github.com/llvm/llvm-project/blob/8ef3e895ad8ab1724e2b87cabad1dacdc7a397a3/llvm/lib/Object/ArchiveWriter.cpp | |
9 | ||
10 | #include "llvm/IR/LLVMContext.h" | |
11 | #include "llvm/Object/ObjectFile.h" | |
487cf647 FG |
12 | |
13 | using namespace llvm; | |
14 | using namespace llvm::sys; | |
15 | using namespace llvm::object; | |
16 | ||
17 | static bool isArchiveSymbol(const object::BasicSymbolRef &S) { | |
18 | Expected<uint32_t> SymFlagsOrErr = S.getFlags(); | |
19 | if (!SymFlagsOrErr) | |
20 | // FIXME: Actually report errors helpfully. | |
21 | report_fatal_error(SymFlagsOrErr.takeError()); | |
22 | if (*SymFlagsOrErr & object::SymbolRef::SF_FormatSpecific) | |
23 | return false; | |
24 | if (!(*SymFlagsOrErr & object::SymbolRef::SF_Global)) | |
25 | return false; | |
26 | if (*SymFlagsOrErr & object::SymbolRef::SF_Undefined) | |
27 | return false; | |
28 | return true; | |
29 | } | |
30 | ||
31 | typedef void *(*LLVMRustGetSymbolsCallback)(void *, const char *); | |
32 | typedef void *(*LLVMRustGetSymbolsErrorCallback)(const char *); | |
33 | ||
34 | // Note: This is implemented in C++ instead of using the C api from Rust as IRObjectFile doesn't | |
35 | // implement getSymbolName, only printSymbolName, which is inaccessible from the C api. | |
36 | extern "C" void *LLVMRustGetSymbols( | |
37 | char *BufPtr, size_t BufLen, void *State, LLVMRustGetSymbolsCallback Callback, | |
38 | LLVMRustGetSymbolsErrorCallback ErrorCallback) { | |
39 | std::unique_ptr<MemoryBuffer> Buf = | |
40 | MemoryBuffer::getMemBuffer(StringRef(BufPtr, BufLen), StringRef("LLVMRustGetSymbolsObject"), | |
41 | false); | |
42 | SmallString<0> SymNameBuf; | |
43 | raw_svector_ostream SymName(SymNameBuf); | |
44 | ||
45 | // In the scenario when LLVMContext is populated SymbolicFile will contain a | |
46 | // reference to it, thus SymbolicFile should be destroyed first. | |
47 | LLVMContext Context; | |
48 | std::unique_ptr<object::SymbolicFile> Obj; | |
49 | ||
50 | const file_magic Type = identify_magic(Buf->getBuffer()); | |
51 | if (!object::SymbolicFile::isSymbolicFile(Type, &Context)) { | |
52 | return 0; | |
53 | } | |
54 | ||
55 | if (Type == file_magic::bitcode) { | |
56 | auto ObjOrErr = object::SymbolicFile::createSymbolicFile( | |
57 | Buf->getMemBufferRef(), file_magic::bitcode, &Context); | |
58 | if (!ObjOrErr) { | |
59 | Error E = ObjOrErr.takeError(); | |
60 | SmallString<0> ErrorBuf; | |
61 | raw_svector_ostream Error(ErrorBuf); | |
62 | Error << E << '\0'; | |
63 | return ErrorCallback(Error.str().data()); | |
64 | } | |
65 | Obj = std::move(*ObjOrErr); | |
66 | } else { | |
67 | auto ObjOrErr = object::SymbolicFile::createSymbolicFile(Buf->getMemBufferRef()); | |
68 | if (!ObjOrErr) { | |
69 | Error E = ObjOrErr.takeError(); | |
70 | SmallString<0> ErrorBuf; | |
71 | raw_svector_ostream Error(ErrorBuf); | |
72 | Error << E << '\0'; | |
73 | return ErrorCallback(Error.str().data()); | |
74 | } | |
75 | Obj = std::move(*ObjOrErr); | |
76 | } | |
77 | ||
78 | ||
79 | for (const object::BasicSymbolRef &S : Obj->symbols()) { | |
80 | if (!isArchiveSymbol(S)) | |
81 | continue; | |
82 | if (Error E = S.printName(SymName)) { | |
83 | SmallString<0> ErrorBuf; | |
84 | raw_svector_ostream Error(ErrorBuf); | |
85 | Error << E << '\0'; | |
86 | return ErrorCallback(Error.str().data()); | |
87 | } | |
88 | SymName << '\0'; | |
89 | if (void *E = Callback(State, SymNameBuf.str().data())) { | |
90 | return E; | |
91 | } | |
92 | SymNameBuf.clear(); | |
93 | } | |
94 | return 0; | |
95 | } |