]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_llvm/llvm-wrapper/SymbolWrapper.cpp
Auto merge of #105018 - zertosh:path_buf_deref_mut, r=dtolnay
[rust.git] / compiler / rustc_llvm / llvm-wrapper / SymbolWrapper.cpp
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"
12 #include "llvm/ADT/Optional.h"
13
14 using namespace llvm;
15 using namespace llvm::sys;
16 using namespace llvm::object;
17
18 static bool isArchiveSymbol(const object::BasicSymbolRef &S) {
19   Expected<uint32_t> SymFlagsOrErr = S.getFlags();
20   if (!SymFlagsOrErr)
21     // FIXME: Actually report errors helpfully.
22     report_fatal_error(SymFlagsOrErr.takeError());
23   if (*SymFlagsOrErr & object::SymbolRef::SF_FormatSpecific)
24     return false;
25   if (!(*SymFlagsOrErr & object::SymbolRef::SF_Global))
26     return false;
27   if (*SymFlagsOrErr & object::SymbolRef::SF_Undefined)
28     return false;
29   return true;
30 }
31
32 typedef void *(*LLVMRustGetSymbolsCallback)(void *, const char *);
33 typedef void *(*LLVMRustGetSymbolsErrorCallback)(const char *);
34
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"),
42                                false);
43   SmallString<0> SymNameBuf;
44   raw_svector_ostream SymName(SymNameBuf);
45
46   // In the scenario when LLVMContext is populated SymbolicFile will contain a
47   // reference to it, thus SymbolicFile should be destroyed first.
48   LLVMContext Context;
49   std::unique_ptr<object::SymbolicFile> Obj;
50
51   const file_magic Type = identify_magic(Buf->getBuffer());
52   if (!object::SymbolicFile::isSymbolicFile(Type, &Context)) {
53     return 0;
54   }
55
56   if (Type == file_magic::bitcode) {
57     auto ObjOrErr = object::SymbolicFile::createSymbolicFile(
58       Buf->getMemBufferRef(), file_magic::bitcode, &Context);
59     if (!ObjOrErr) {
60       Error E = ObjOrErr.takeError();
61       SmallString<0> ErrorBuf;
62       raw_svector_ostream Error(ErrorBuf);
63       Error << E << '\0';
64       return ErrorCallback(Error.str().data());
65     }
66     Obj = std::move(*ObjOrErr);
67   } else {
68     auto ObjOrErr = object::SymbolicFile::createSymbolicFile(Buf->getMemBufferRef());
69     if (!ObjOrErr) {
70       Error E = ObjOrErr.takeError();
71       SmallString<0> ErrorBuf;
72       raw_svector_ostream Error(ErrorBuf);
73       Error << E << '\0';
74       return ErrorCallback(Error.str().data());
75     }
76     Obj = std::move(*ObjOrErr);
77   }
78
79
80   for (const object::BasicSymbolRef &S : Obj->symbols()) {
81     if (!isArchiveSymbol(S))
82       continue;
83     if (Error E = S.printName(SymName)) {
84       SmallString<0> ErrorBuf;
85       raw_svector_ostream Error(ErrorBuf);
86       Error << E << '\0';
87       return ErrorCallback(Error.str().data());
88     }
89     SymName << '\0';
90     if (void *E = Callback(State, SymNameBuf.str().data())) {
91       return E;
92     }
93     SymNameBuf.clear();
94   }
95   return 0;
96 }