LLVMCreateDisasm returns NULL

I am trying to parse some bytes using the LLVM C interface. However, LLVMCreateDisasm() returns NULL.

 #include <stdio.h> // printf() #include <stdlib.h> // EXIT_FAILURE, EXIT_SUCCESS #define __STDC_CONSTANT_MACROS // llvm complains otherwise #define __STDC_LIMIT_MACROS #include <llvm-c/Disassembler.h> int main() { LLVMDisasmContextRef dc = LLVMCreateDisasm ( "testname", NULL, 0, NULL, NULL ); if (dc == NULL) { printf("Could not create disassembler"); return EXIT_FAILURE; } return EXIT_SUCCESS; } 

I am on x64 Linux. Looking at the documentation, it looks like I'm doing everything right.

 LLVMDisasmContextRef LLVMCreateDisasm ( const char * TripleName, void * DisInfo, int TagType, LLVMOpInfoCallback GetOpInfo, LLVMSymbolLookupCallback SymbolLookUp ) 

Create a disassembler for TripleName. Symbolic disassembly is supported by passing a block of information in the DisInfo parameter and specifying the TagType and callback functions, as described above. All of them can be passed as NULL. If successful, this returns a disassembler context. If not, it returns NULL.

Update

  • My llvm version is 3.4
  • I tried all the possible triple / goals that I could think of, anyway.
  • Insert printf in lib / MC / MCDisassembler / Disassembler.cpp: LLVMCreateDisasmCPU () and it will not work on the first if check. Error line at this point "Unable to find target for this triple (no targets are registered)"

     LLVMDisasmContextRef LLVMCreateDisasmCPU(const char *Triple, const char *CPU, void *DisInfo, int TagType, LLVMOpInfoCallback GetOpInfo, LLVMSymbolLookupCallback SymbolLookUp){ std::cout << ">>> Triplename: " << Triple << std::endl; // Get the target. std::string Error; const Target *TheTarget = TargetRegistry::lookupTarget(Triple, Error); if (!TheTarget) { std::cout << "Failed 1: " << Error << std::endl; return 0; } ... 

    So, it fails when calling lookupTarget .

  • Looking at lib / Support / TargetRegistry.cpp: lookupTarget () the first if check fails. There are some tips in the comment:

     const Target *TargetRegistry::lookupTarget(const std::string &TT, std::string &Error) { // Provide special warning when no targets are initialized. if (begin() == end()) { Error = "Unable to find target for this triple (no targets are registered)"; return 0; } ... 

    So, I need to initialize the target first.

  • In my code, I first call LLVMInitializeAllTargetInfos(); from the llvm-c/Target.h . Now it does not work in the second if validation of Disassembler.cpp: LLVMCreateDisasmCPU ()

     const MCRegisterInfo *MRI = TheTarget->createMCRegInfo(Triple); if (!MRI) { std::cout << "Failed 2: " << Error << std::endl; return 0; } 

    with this line Error : Could not create disassembler

Finally decided!

I just needed to call LLVMInitializeAllTargetInfos(); , LLVMInitializeAllTargetMCs(); , LLVMInitializeAllDisassemblers(); before creating the context of the disorder:

 #include <stdio.h> // printf() #include <stdlib.h> // EXIT_FAILURE, EXIT_SUCCESS #define __STDC_CONSTANT_MACROS // llvm complains otherwise #define __STDC_LIMIT_MACROS #include <llvm-c/Disassembler.h> #include <llvm-c/Target.h> int main() { LLVMInitializeAllTargetInfos(); LLVMInitializeAllTargetMCs(); LLVMInitializeAllDisassemblers(); LLVMDisasmContextRef dc = LLVMCreateDisasm ( "x86_64-unknown-linux-gnu", NULL, 0, NULL, NULL ); if (dc == NULL) { printf("Could not create disassembler"); return EXIT_FAILURE; } return EXIT_SUCCESS; } 
+8
c disassembly llvm
source share
1 answer

The first argument is LLVMCreateDisasm ,

 "testname" 

Invalid TripleName . TripleName will instruct LLVM on what your goal is, and this is necessary because LLVM contains support for multiple goals in one installation.

You can specify supported target architectures by running the command

 llc -version 

And there are goals for x86 and x86_64

 x86 - 32-bit X86: Pentium-Pro and above x86-64 - 64-bit X86: EM64T and AMD64 

To build the correct TripleName name, you need to find some good subarch (i486 or x86_64) for your purpose, then add the provider and OS:

http://llvm.org/docs/doxygen/html/Triple_8h_source.html

 00022 /// Triple - Helper class for working with autoconf configuration names. For 00023 /// historical reasons, we also call these 'triples' (they used to contain 00024 /// exactly three fields). 00025 /// 00026 /// Configuration names are strings in the canonical form: 00027 /// ARCHITECTURE-VENDOR-OPERATING_SYSTEM 00028 /// or 00029 /// ARCHITECTURE-VENDOR-OPERATING_SYSTEM-ENVIRONMENT 

ArchType enumerations are listed here, with a list of recognized Arch in the comment (actual parser lib / Support / Triple.cpp - parseArch ), for example

 arm, // ARM: arm, armv.*, xscale aarch64, // AArch64: aarch64 .... x86, // X86: i[3-9]86 x86_64, // X86-64: amd64, x86_64 

The same file has valid providers ( enum VendorType ), OS types ( enum OSType ) and Envronments ( enum EnvironmentType ). In most cases, you can use "unknown" for providers and os, but "-unknown-linux-gnu" is often used.

Some examples of valid TripleName s:

 x86_64--linux-gnu x86_64-unknown-linux-gnu i486--linux-gnu 

The following is a description of the actual clang triples: http://clang.llvm.org/docs/CrossCompilation.html and some valid names listed in https://stackoverflow.com/a/3/3/2 ...

Another limitation in LLVMCreateDisasm is that not all targets have an implemented MCDisassembler . For example, in LLVM-2.9 there are MCDissasemblers files only for X86, X86_64, ARM, and MBlaze; in later (svn from 2014-02-01) also for Sparc, PPC, MIPS, SystemZ, XCore and AArch64.

If you could not create MCDisassembler even with the correct triple, there are several options for debugging the LLVMCreateDisasmCPU function from the MC / MCDisassembler / Disassembler.cpp file. You can break into gdb and then do the β€œnext” -stepping before the error (this will be more beautiful and easier with the debug build of LLVM); or you can add printf debugging to the LLVMCreateDisasmCPU value or a temporary change returned from simple NULL information that is different from every error.

UPDATE: It seems that your LLVM was not initialized during the conversation. LLVM (~ 3.4 or later) has many LLVM initializers in the llvm-c / Target.h header :

LLVMInitializeAllTargetInfos() - The main program must call this function if it wants to access all available objects for which LLVM is configured to support.

LLVMInitializeAllTargets() - The main program should call this function if it wants to link all the available goals for which LLVM is configured to support.

LLVMInitializeAllTargetMCs() - The main program should call this function if it wants to access all available target MCs that LLVM is configured to support.

LLVMInitializeAllDisassemblers() - The main program should call this function if it wants all disassemblers to be configured to support LLVM, to make them accessible through TargetRegistry.

LLVMInitializeAllAsmPrinters() - The main program should call this function if it wants all asm printers that LLVM is configured to support to make them accessible through TargetRegistry.

etc. ( https://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm-c/Target.h?logsort=rev&diff_format=h&r1=192697&r2=192696&pathrev=192697 ).

There is even a LLVMInitializeNativeTarget function that initializes its own object:

LLVMInitializeNativeTarget() - The main program should call this function to initialize its own target corresponding to the host. This is useful for JIT applications to ensure proper target binding.

+6
source share

All Articles