| //===- Object.cpp - C bindings to the object file library--------*- C++ -*-===// | |
| // | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| // See https://llvm.org/LICENSE.txt for license information. | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| // | |
| //===----------------------------------------------------------------------===// | |
| // | |
| // This file defines the C bindings to the file-format-independent object | |
| // library. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "llvm-c/Object.h" | |
| #include "llvm/ADT/SmallVector.h" | |
| #include "llvm/IR/LLVMContext.h" | |
| #include "llvm/Object/ObjectFile.h" | |
| #include "llvm/Object/MachOUniversal.h" | |
| #include "llvm/Support/MemAlloc.h" | |
| using namespace llvm; | |
| using namespace object; | |
| inline OwningBinary<ObjectFile> *unwrap(LLVMObjectFileRef OF) { | |
| return reinterpret_cast<OwningBinary<ObjectFile> *>(OF); | |
| } | |
| inline LLVMObjectFileRef wrap(const OwningBinary<ObjectFile> *OF) { | |
| return reinterpret_cast<LLVMObjectFileRef>( | |
| const_cast<OwningBinary<ObjectFile> *>(OF)); | |
| } | |
| inline section_iterator *unwrap(LLVMSectionIteratorRef SI) { | |
| return reinterpret_cast<section_iterator*>(SI); | |
| } | |
| inline LLVMSectionIteratorRef | |
| wrap(const section_iterator *SI) { | |
| return reinterpret_cast<LLVMSectionIteratorRef> | |
| (const_cast<section_iterator*>(SI)); | |
| } | |
| inline symbol_iterator *unwrap(LLVMSymbolIteratorRef SI) { | |
| return reinterpret_cast<symbol_iterator*>(SI); | |
| } | |
| inline LLVMSymbolIteratorRef | |
| wrap(const symbol_iterator *SI) { | |
| return reinterpret_cast<LLVMSymbolIteratorRef> | |
| (const_cast<symbol_iterator*>(SI)); | |
| } | |
| inline relocation_iterator *unwrap(LLVMRelocationIteratorRef SI) { | |
| return reinterpret_cast<relocation_iterator*>(SI); | |
| } | |
| inline LLVMRelocationIteratorRef | |
| wrap(const relocation_iterator *SI) { | |
| return reinterpret_cast<LLVMRelocationIteratorRef> | |
| (const_cast<relocation_iterator*>(SI)); | |
| } | |
| /*--.. Operations on binary files ..........................................--*/ | |
| LLVMBinaryRef LLVMCreateBinary(LLVMMemoryBufferRef MemBuf, | |
| LLVMContextRef Context, | |
| char **ErrorMessage) { | |
| auto maybeContext = Context ? unwrap(Context) : nullptr; | |
| Expected<std::unique_ptr<Binary>> ObjOrErr( | |
| createBinary(unwrap(MemBuf)->getMemBufferRef(), maybeContext)); | |
| if (!ObjOrErr) { | |
| *ErrorMessage = strdup(toString(ObjOrErr.takeError()).c_str()); | |
| return nullptr; | |
| } | |
| return wrap(ObjOrErr.get().release()); | |
| } | |
| LLVMMemoryBufferRef LLVMBinaryCopyMemoryBuffer(LLVMBinaryRef BR) { | |
| auto Buf = unwrap(BR)->getMemoryBufferRef(); | |
| return wrap(llvm::MemoryBuffer::getMemBuffer( | |
| Buf.getBuffer(), Buf.getBufferIdentifier(), | |
| /*RequiresNullTerminator*/false).release()); | |
| } | |
| void LLVMDisposeBinary(LLVMBinaryRef BR) { | |
| delete unwrap(BR); | |
| } | |
| LLVMBinaryType LLVMBinaryGetType(LLVMBinaryRef BR) { | |
| class BinaryTypeMapper final : public Binary { | |
| public: | |
| static LLVMBinaryType mapBinaryTypeToLLVMBinaryType(unsigned Kind) { | |
| switch (Kind) { | |
| case ID_Archive: | |
| return LLVMBinaryTypeArchive; | |
| case ID_MachOUniversalBinary: | |
| return LLVMBinaryTypeMachOUniversalBinary; | |
| case ID_COFFImportFile: | |
| return LLVMBinaryTypeCOFFImportFile; | |
| case ID_IR: | |
| return LLVMBinaryTypeIR; | |
| case ID_WinRes: | |
| return LLVMBinaryTypeWinRes; | |
| case ID_COFF: | |
| return LLVMBinaryTypeCOFF; | |
| case ID_ELF32L: | |
| return LLVMBinaryTypeELF32L; | |
| case ID_ELF32B: | |
| return LLVMBinaryTypeELF32B; | |
| case ID_ELF64L: | |
| return LLVMBinaryTypeELF64L; | |
| case ID_ELF64B: | |
| return LLVMBinaryTypeELF64B; | |
| case ID_MachO32L: | |
| return LLVMBinaryTypeMachO32L; | |
| case ID_MachO32B: | |
| return LLVMBinaryTypeMachO32B; | |
| case ID_MachO64L: | |
| return LLVMBinaryTypeMachO64L; | |
| case ID_MachO64B: | |
| return LLVMBinaryTypeMachO64B; | |
| case ID_Offload: | |
| return LLVMBinaryTypeOffload; | |
| case ID_Wasm: | |
| return LLVMBinaryTypeWasm; | |
| case ID_DXContainer: | |
| return LLVMBinaryTypeDXcontainer; | |
| case ID_StartObjects: | |
| case ID_EndObjects: | |
| llvm_unreachable("Marker types are not valid binary kinds!"); | |
| default: | |
| llvm_unreachable("Unknown binary kind!"); | |
| } | |
| } | |
| }; | |
| return BinaryTypeMapper::mapBinaryTypeToLLVMBinaryType(unwrap(BR)->getType()); | |
| } | |
| LLVMBinaryRef LLVMMachOUniversalBinaryCopyObjectForArch(LLVMBinaryRef BR, | |
| const char *Arch, | |
| size_t ArchLen, | |
| char **ErrorMessage) { | |
| auto universal = cast<MachOUniversalBinary>(unwrap(BR)); | |
| Expected<std::unique_ptr<ObjectFile>> ObjOrErr( | |
| universal->getMachOObjectForArch({Arch, ArchLen})); | |
| if (!ObjOrErr) { | |
| *ErrorMessage = strdup(toString(ObjOrErr.takeError()).c_str()); | |
| return nullptr; | |
| } | |
| return wrap(ObjOrErr.get().release()); | |
| } | |
| LLVMSectionIteratorRef LLVMObjectFileCopySectionIterator(LLVMBinaryRef BR) { | |
| auto OF = cast<ObjectFile>(unwrap(BR)); | |
| auto sections = OF->sections(); | |
| if (sections.begin() == sections.end()) | |
| return nullptr; | |
| return wrap(new section_iterator(sections.begin())); | |
| } | |
| LLVMBool LLVMObjectFileIsSectionIteratorAtEnd(LLVMBinaryRef BR, | |
| LLVMSectionIteratorRef SI) { | |
| auto OF = cast<ObjectFile>(unwrap(BR)); | |
| return (*unwrap(SI) == OF->section_end()) ? 1 : 0; | |
| } | |
| LLVMSymbolIteratorRef LLVMObjectFileCopySymbolIterator(LLVMBinaryRef BR) { | |
| auto OF = cast<ObjectFile>(unwrap(BR)); | |
| auto symbols = OF->symbols(); | |
| if (symbols.begin() == symbols.end()) | |
| return nullptr; | |
| return wrap(new symbol_iterator(symbols.begin())); | |
| } | |
| LLVMBool LLVMObjectFileIsSymbolIteratorAtEnd(LLVMBinaryRef BR, | |
| LLVMSymbolIteratorRef SI) { | |
| auto OF = cast<ObjectFile>(unwrap(BR)); | |
| return (*unwrap(SI) == OF->symbol_end()) ? 1 : 0; | |
| } | |
| // ObjectFile creation | |
| LLVMObjectFileRef LLVMCreateObjectFile(LLVMMemoryBufferRef MemBuf) { | |
| std::unique_ptr<MemoryBuffer> Buf(unwrap(MemBuf)); | |
| Expected<std::unique_ptr<ObjectFile>> ObjOrErr( | |
| ObjectFile::createObjectFile(Buf->getMemBufferRef())); | |
| if (!ObjOrErr) { | |
| // TODO: Actually report errors helpfully. | |
| consumeError(ObjOrErr.takeError()); | |
| return nullptr; | |
| } | |
| auto *Ret = new OwningBinary<ObjectFile>(std::move(ObjOrErr.get()), std::move(Buf)); | |
| return wrap(Ret); | |
| } | |
| void LLVMDisposeObjectFile(LLVMObjectFileRef ObjectFile) { | |
| delete unwrap(ObjectFile); | |
| } | |
| // ObjectFile Section iterators | |
| LLVMSectionIteratorRef LLVMGetSections(LLVMObjectFileRef OF) { | |
| OwningBinary<ObjectFile> *OB = unwrap(OF); | |
| section_iterator SI = OB->getBinary()->section_begin(); | |
| return wrap(new section_iterator(SI)); | |
| } | |
| void LLVMDisposeSectionIterator(LLVMSectionIteratorRef SI) { | |
| delete unwrap(SI); | |
| } | |
| LLVMBool LLVMIsSectionIteratorAtEnd(LLVMObjectFileRef OF, | |
| LLVMSectionIteratorRef SI) { | |
| OwningBinary<ObjectFile> *OB = unwrap(OF); | |
| return (*unwrap(SI) == OB->getBinary()->section_end()) ? 1 : 0; | |
| } | |
| void LLVMMoveToNextSection(LLVMSectionIteratorRef SI) { | |
| ++(*unwrap(SI)); | |
| } | |
| void LLVMMoveToContainingSection(LLVMSectionIteratorRef Sect, | |
| LLVMSymbolIteratorRef Sym) { | |
| Expected<section_iterator> SecOrErr = (*unwrap(Sym))->getSection(); | |
| if (!SecOrErr) { | |
| std::string Buf; | |
| raw_string_ostream OS(Buf); | |
| logAllUnhandledErrors(SecOrErr.takeError(), OS); | |
| report_fatal_error(Twine(OS.str())); | |
| } | |
| *unwrap(Sect) = *SecOrErr; | |
| } | |
| // ObjectFile Symbol iterators | |
| LLVMSymbolIteratorRef LLVMGetSymbols(LLVMObjectFileRef OF) { | |
| OwningBinary<ObjectFile> *OB = unwrap(OF); | |
| symbol_iterator SI = OB->getBinary()->symbol_begin(); | |
| return wrap(new symbol_iterator(SI)); | |
| } | |
| void LLVMDisposeSymbolIterator(LLVMSymbolIteratorRef SI) { | |
| delete unwrap(SI); | |
| } | |
| LLVMBool LLVMIsSymbolIteratorAtEnd(LLVMObjectFileRef OF, | |
| LLVMSymbolIteratorRef SI) { | |
| OwningBinary<ObjectFile> *OB = unwrap(OF); | |
| return (*unwrap(SI) == OB->getBinary()->symbol_end()) ? 1 : 0; | |
| } | |
| void LLVMMoveToNextSymbol(LLVMSymbolIteratorRef SI) { | |
| ++(*unwrap(SI)); | |
| } | |
| // SectionRef accessors | |
| const char *LLVMGetSectionName(LLVMSectionIteratorRef SI) { | |
| auto NameOrErr = (*unwrap(SI))->getName(); | |
| if (!NameOrErr) | |
| report_fatal_error(NameOrErr.takeError()); | |
| return NameOrErr->data(); | |
| } | |
| uint64_t LLVMGetSectionSize(LLVMSectionIteratorRef SI) { | |
| return (*unwrap(SI))->getSize(); | |
| } | |
| const char *LLVMGetSectionContents(LLVMSectionIteratorRef SI) { | |
| if (Expected<StringRef> E = (*unwrap(SI))->getContents()) | |
| return E->data(); | |
| else | |
| report_fatal_error(E.takeError()); | |
| } | |
| uint64_t LLVMGetSectionAddress(LLVMSectionIteratorRef SI) { | |
| return (*unwrap(SI))->getAddress(); | |
| } | |
| LLVMBool LLVMGetSectionContainsSymbol(LLVMSectionIteratorRef SI, | |
| LLVMSymbolIteratorRef Sym) { | |
| return (*unwrap(SI))->containsSymbol(**unwrap(Sym)); | |
| } | |
| // Section Relocation iterators | |
| LLVMRelocationIteratorRef LLVMGetRelocations(LLVMSectionIteratorRef Section) { | |
| relocation_iterator SI = (*unwrap(Section))->relocation_begin(); | |
| return wrap(new relocation_iterator(SI)); | |
| } | |
| void LLVMDisposeRelocationIterator(LLVMRelocationIteratorRef SI) { | |
| delete unwrap(SI); | |
| } | |
| LLVMBool LLVMIsRelocationIteratorAtEnd(LLVMSectionIteratorRef Section, | |
| LLVMRelocationIteratorRef SI) { | |
| return (*unwrap(SI) == (*unwrap(Section))->relocation_end()) ? 1 : 0; | |
| } | |
| void LLVMMoveToNextRelocation(LLVMRelocationIteratorRef SI) { | |
| ++(*unwrap(SI)); | |
| } | |
| // SymbolRef accessors | |
| const char *LLVMGetSymbolName(LLVMSymbolIteratorRef SI) { | |
| Expected<StringRef> Ret = (*unwrap(SI))->getName(); | |
| if (!Ret) { | |
| std::string Buf; | |
| raw_string_ostream OS(Buf); | |
| logAllUnhandledErrors(Ret.takeError(), OS); | |
| report_fatal_error(Twine(OS.str())); | |
| } | |
| return Ret->data(); | |
| } | |
| uint64_t LLVMGetSymbolAddress(LLVMSymbolIteratorRef SI) { | |
| Expected<uint64_t> Ret = (*unwrap(SI))->getAddress(); | |
| if (!Ret) { | |
| std::string Buf; | |
| raw_string_ostream OS(Buf); | |
| logAllUnhandledErrors(Ret.takeError(), OS); | |
| report_fatal_error(Twine(OS.str())); | |
| } | |
| return *Ret; | |
| } | |
| uint64_t LLVMGetSymbolSize(LLVMSymbolIteratorRef SI) { | |
| return (*unwrap(SI))->getCommonSize(); | |
| } | |
| // RelocationRef accessors | |
| uint64_t LLVMGetRelocationOffset(LLVMRelocationIteratorRef RI) { | |
| return (*unwrap(RI))->getOffset(); | |
| } | |
| LLVMSymbolIteratorRef LLVMGetRelocationSymbol(LLVMRelocationIteratorRef RI) { | |
| symbol_iterator ret = (*unwrap(RI))->getSymbol(); | |
| return wrap(new symbol_iterator(ret)); | |
| } | |
| uint64_t LLVMGetRelocationType(LLVMRelocationIteratorRef RI) { | |
| return (*unwrap(RI))->getType(); | |
| } | |
| // NOTE: Caller takes ownership of returned string. | |
| const char *LLVMGetRelocationTypeName(LLVMRelocationIteratorRef RI) { | |
| SmallVector<char, 0> ret; | |
| (*unwrap(RI))->getTypeName(ret); | |
| char *str = static_cast<char*>(safe_malloc(ret.size())); | |
| llvm::copy(ret, str); | |
| return str; | |
| } | |
| // NOTE: Caller takes ownership of returned string. | |
| const char *LLVMGetRelocationValueString(LLVMRelocationIteratorRef RI) { | |
| return strdup(""); | |
| } | |