1#include <stdio.h>
2#include <stdlib.h>
3#include <libc.h>
4#include <sys/file.h>
5#include <dlfcn.h>
6#include "llvm-c/Disassembler.h"
7#include "stuff/llvm.h"
8#include "stuff/allocate.h"
9#include <mach-o/dyld.h>
10
11/*
12 * The disassembler API is currently exported from libLTO.dylib.  Eventually we
13 * plan to include it (along with the current libLTO APIs) in a generic
14 * libLLVM.dylib.
15 */
16#define LIB_LLVM "libLTO.dylib"
17
18static int tried_to_load_llvm = 0;
19static void *llvm_handle = NULL;
20static void (*initialize)(void) = NULL;
21static LLVMDisasmContextRef (*create)(const char *, void *, int,
22	LLVMOpInfoCallback, LLVMSymbolLookupCallback) = NULL;
23static LLVMDisasmContextRef (*createCPU)(const char *, const char *,void *, int,
24	LLVMOpInfoCallback, LLVMSymbolLookupCallback) = NULL;
25static void (*dispose)(LLVMDisasmContextRef) = NULL;
26static size_t (*disasm)(LLVMDisasmContextRef, uint8_t *, uint64_t, uint64_t,
27	char *, size_t) = NULL;
28static int (*options)(LLVMDisasmContextRef, uint64_t) = NULL;
29
30/*
31 * Wrapper to dynamically load LIB_LLVM and call LLVMCreateDisasm().
32 */
33__private_extern__
34LLVMDisasmContextRef
35llvm_create_disasm(
36const char *TripleName,
37const char *CPU,
38void *DisInfo,
39int TagType,
40LLVMOpInfoCallback GetOpInfo,
41LLVMSymbolLookupCallback SymbolLookUp)
42{
43   uint32_t bufsize;
44   char *p, *prefix, *llvm_path, buf[MAXPATHLEN], resolved_name[PATH_MAX];
45   int i;
46   LLVMDisasmContextRef DC;
47
48	if(tried_to_load_llvm == 0){
49	    tried_to_load_llvm = 1;
50	    /*
51	     * Construct the prefix to this executable assuming it is in a bin
52	     * directory relative to a lib directory of the matching lto library
53	     * and first try to load that.  If not then fall back to trying
54	     * "/Applications/Xcode.app/Contents/Developer/Toolchains/
55	     * XcodeDefault.xctoolchain/usr/lib/" LIB_LLVM.
56	     */
57	    bufsize = MAXPATHLEN;
58	    p = buf;
59	    i = _NSGetExecutablePath(p, &bufsize);
60	    if(i == -1){
61		p = allocate(bufsize);
62		_NSGetExecutablePath(p, &bufsize);
63	    }
64	    prefix = realpath(p, resolved_name);
65	    p = rindex(prefix, '/');
66	    if(p != NULL)
67		p[1] = '\0';
68	    llvm_path = makestr(prefix, "../lib/" LIB_LLVM, NULL);
69
70	    llvm_handle = dlopen(llvm_path, RTLD_NOW);
71	    if(llvm_handle == NULL){
72		free(llvm_path);
73		llvm_path = NULL;
74		llvm_handle = dlopen("/Applications/Xcode.app/Contents/"
75				     "Developer/Toolchains/XcodeDefault."
76				     "xctoolchain/usr/lib/" LIB_LLVM,
77				     RTLD_NOW);
78	    }
79	    if(llvm_handle == NULL)
80		return(0);
81
82	    create = dlsym(llvm_handle, "LLVMCreateDisasm");
83	    dispose = dlsym(llvm_handle, "LLVMDisasmDispose");
84	    disasm = dlsym(llvm_handle, "LLVMDisasmInstruction");
85
86	    /* Note we allow these to not be defined */
87	    options = dlsym(llvm_handle, "LLVMSetDisasmOptions");
88	    createCPU = dlsym(llvm_handle, "LLVMCreateDisasmCPU");
89
90	    if(create == NULL ||
91	       dispose == NULL ||
92	       disasm == NULL){
93
94		dlclose(llvm_handle);
95		if(llvm_path != NULL)
96		    free(llvm_path);
97		llvm_handle = NULL;
98		create = NULL;
99		createCPU = NULL;
100		dispose = NULL;
101		disasm = NULL;
102		options = NULL;
103		return(NULL);
104	    }
105	}
106	if(llvm_handle == NULL)
107	    return(NULL);
108
109	/*
110	 * Note this was added after the interface was defined, so it may
111	 * be undefined.  But if not we must call it first.
112	 */
113	initialize = dlsym(llvm_handle, "lto_initialize_disassembler");
114	if(initialize != NULL)
115	    initialize();
116
117	if(*CPU != '\0' && createCPU != NULL)
118	    DC = createCPU(TripleName, CPU, DisInfo, TagType, GetOpInfo,
119			   SymbolLookUp);
120	else
121	    DC = create(TripleName, DisInfo, TagType, GetOpInfo, SymbolLookUp);
122	return(DC);
123}
124
125/*
126 * Wrapper to call LLVMDisasmDispose().
127 */
128__private_extern__
129void
130llvm_disasm_dispose(
131LLVMDisasmContextRef DC)
132{
133	if(dispose != NULL)
134	    dispose(DC);
135}
136
137/*
138 * Wrapper to call LLVMDisasmInstruction().
139 */
140__private_extern__
141size_t
142llvm_disasm_instruction(
143LLVMDisasmContextRef DC,
144uint8_t *Bytes,
145uint64_t BytesSize,
146uint64_t Pc,
147char *OutString,
148size_t OutStringSize)
149{
150
151	if(disasm == NULL)
152	    return(0);
153	return(disasm(DC, Bytes, BytesSize, Pc, OutString, OutStringSize));
154}
155
156/*
157 * Wrapper to call LLVMSetDisasmOptions().
158 */
159__private_extern__
160int
161llvm_disasm_set_options(
162LLVMDisasmContextRef DC,
163uint64_t Options)
164{
165
166	if(options == NULL)
167	    return(0);
168	return(options(DC, Options));
169}
170