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
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
10 #include "llvm/IR/LLVMContext.h"
11 #include "llvm/Object/ObjectFile.h"
12 #include "llvm/ADT/Optional.h"
15 using namespace llvm::sys;
16 using namespace llvm::object;
18 static bool isArchiveSymbol(const object::BasicSymbolRef &S) {
19 Expected<uint32_t> SymFlagsOrErr = S.getFlags();
21 // FIXME: Actually report errors helpfully.
22 report_fatal_error(SymFlagsOrErr.takeError());
23 if (*SymFlagsOrErr & object::SymbolRef::SF_FormatSpecific)
25 if (!(*SymFlagsOrErr & object::SymbolRef::SF_Global))
27 if (*SymFlagsOrErr & object::SymbolRef::SF_Undefined)
32 typedef void *(*LLVMRustGetSymbolsCallback)(void *, const char *);
33 typedef void *(*LLVMRustGetSymbolsErrorCallback)(const char *);
35 // Note: This is implemented in C++ instead of using the C api from Rust as IRObjectFile doesn't
36 // implement getSymbolName, only printSymbolName, which is inaccessible from the C api.
37 extern "C" void *LLVMRustGetSymbols(
38 char *BufPtr, size_t BufLen, void *State, LLVMRustGetSymbolsCallback Callback,
39 LLVMRustGetSymbolsErrorCallback ErrorCallback) {
40 std::unique_ptr<MemoryBuffer> Buf =
41 MemoryBuffer::getMemBuffer(StringRef(BufPtr, BufLen), StringRef("LLVMRustGetSymbolsObject"),
43 SmallString<0> SymNameBuf;
44 raw_svector_ostream SymName(SymNameBuf);
46 // In the scenario when LLVMContext is populated SymbolicFile will contain a
47 // reference to it, thus SymbolicFile should be destroyed first.
49 std::unique_ptr<object::SymbolicFile> Obj;
51 const file_magic Type = identify_magic(Buf->getBuffer());
52 if (!object::SymbolicFile::isSymbolicFile(Type, &Context)) {
56 if (Type == file_magic::bitcode) {
57 auto ObjOrErr = object::SymbolicFile::createSymbolicFile(
58 Buf->getMemBufferRef(), file_magic::bitcode, &Context);
60 Error E = ObjOrErr.takeError();
61 SmallString<0> ErrorBuf;
62 raw_svector_ostream Error(ErrorBuf);
64 return ErrorCallback(Error.str().data());
66 Obj = std::move(*ObjOrErr);
68 auto ObjOrErr = object::SymbolicFile::createSymbolicFile(Buf->getMemBufferRef());
70 Error E = ObjOrErr.takeError();
71 SmallString<0> ErrorBuf;
72 raw_svector_ostream Error(ErrorBuf);
74 return ErrorCallback(Error.str().data());
76 Obj = std::move(*ObjOrErr);
80 for (const object::BasicSymbolRef &S : Obj->symbols()) {
81 if (!isArchiveSymbol(S))
83 if (Error E = S.printName(SymName)) {
84 SmallString<0> ErrorBuf;
85 raw_svector_ostream Error(ErrorBuf);
87 return ErrorCallback(Error.str().data());
90 if (void *E = Callback(State, SymNameBuf.str().data())) {