2525#include <bpf/libbpf.h>
2626
2727#ifdef HAVE_LLVM_SUPPORT
28- #include <llvm-c/Core.h>
29- #include <llvm-c/Disassembler.h>
30- #include <llvm-c/Target.h>
31- #include <llvm-c/TargetMachine.h>
28+ #include <dlfcn.h>
29+
30+ #include "llvm_disasm.h"
3231#endif
3332
3433#ifdef HAVE_LIBBFD_SUPPORT
@@ -45,7 +44,32 @@ static int oper_count;
4544#ifdef HAVE_LLVM_SUPPORT
4645#define DISASM_SPACER
4746
48- typedef LLVMDisasmContextRef disasm_ctx_t ;
47+ /*
48+ * The libLLVM-based disassembler used for "bpftool prog dump jited" lives in a
49+ * separate plugin, bpftool-llvm.so, which is the only object linked against
50+ * libLLVM. This keeps the bpftool binary itself free of a hard dependency on
51+ * the (large) libLLVM shared object: the plugin is loaded lazily with dlopen()
52+ * the first time a JITed image actually needs to be disassembled, with its
53+ * entry points resolved by dlsym(). See llvm_disasm.c for the plugin.
54+ *
55+ * LLVM_PLUGIN_DIR is the install directory baked in at build time
56+ * ($(libdir)/bpftool). When set, the plugin is loaded from that absolute
57+ * location; otherwise only the bare file name is used, i.e. the plugin is
58+ * looked up via the dynamic linker search path (or the current directory).
59+ */
60+ #ifdef LLVM_PLUGIN_DIR
61+ #define LLVM_PLUGIN_PATH LLVM_PLUGIN_DIR "/bpftool-llvm.so"
62+ #else
63+ #define LLVM_PLUGIN_PATH "bpftool-llvm.so"
64+ #endif
65+
66+ typedef void * disasm_ctx_t ;
67+
68+ static void * llvm_plugin_handle ;
69+ static __typeof__ (& bpftool_llvm_init ) p_bpftool_llvm_init ;
70+ static __typeof__ (& bpftool_llvm_create_context ) p_bpftool_llvm_create_context ;
71+ static __typeof__ (& bpftool_llvm_destroy_context ) p_bpftool_llvm_destroy_context ;
72+ static __typeof__ (& bpftool_llvm_disassemble ) p_bpftool_llvm_disassemble ;
4973
5074static int printf_json (char * s )
5175{
@@ -63,18 +87,39 @@ static int printf_json(char *s)
6387 return 0 ;
6488}
6589
66- /* This callback to set the ref_type is necessary to have the LLVM disassembler
67- * print PC-relative addresses instead of byte offsets for branch instruction
68- * targets.
69- */
70- static const char *
71- symbol_lookup_callback (__maybe_unused void * disasm_info ,
72- __maybe_unused uint64_t ref_value ,
73- uint64_t * ref_type , __maybe_unused uint64_t ref_PC ,
74- __maybe_unused const char * * ref_name )
90+ static int load_llvm_plugin (void )
7591{
76- * ref_type = LLVMDisassembler_ReferenceType_InOut_None ;
77- return NULL ;
92+ if (llvm_plugin_handle )
93+ return 0 ;
94+
95+ /* Load the plugin by its absolute install path. */
96+ llvm_plugin_handle = dlopen (LLVM_PLUGIN_PATH , RTLD_NOW | RTLD_LOCAL );
97+ if (!llvm_plugin_handle ) {
98+ p_err ("failed to load %s, install it to disassemble JITed programs: %s" ,
99+ LLVM_PLUGIN_PATH , dlerror ());
100+ return -1 ;
101+ }
102+
103+ #define RESOLVE (name ) \
104+ do { \
105+ p_##name = (__typeof__(p_##name))dlsym(llvm_plugin_handle, \
106+ #name); \
107+ if (!p_##name) { \
108+ p_err("%s is missing symbol %s: %s", \
109+ LLVM_PLUGIN_PATH, #name, dlerror()); \
110+ dlclose(llvm_plugin_handle); \
111+ llvm_plugin_handle = NULL; \
112+ return -1; \
113+ } \
114+ } while (0)
115+
116+ RESOLVE (bpftool_llvm_init );
117+ RESOLVE (bpftool_llvm_create_context );
118+ RESOLVE (bpftool_llvm_destroy_context );
119+ RESOLVE (bpftool_llvm_disassemble );
120+ #undef RESOLVE
121+
122+ return 0 ;
78123}
79124
80125static int
@@ -83,28 +128,7 @@ init_context(disasm_ctx_t *ctx, const char *arch,
83128 __maybe_unused unsigned char * image , __maybe_unused ssize_t len ,
84129 __maybe_unused __u64 func_ksym )
85130{
86- char * triple ;
87-
88- if (arch )
89- triple = LLVMNormalizeTargetTriple (arch );
90- else
91- triple = LLVMGetDefaultTargetTriple ();
92- if (!triple ) {
93- p_err ("Failed to retrieve triple" );
94- return -1 ;
95- }
96-
97- /*
98- * Enable all aarch64 ISA extensions so the disassembler can handle any
99- * instruction the kernel JIT might emit (e.g. ARM64 LSE atomics).
100- */
101- if (!strncmp (triple , "aarch64" , 7 ))
102- * ctx = LLVMCreateDisasmCPUFeatures (triple , "" , "+all" , NULL , 0 , NULL ,
103- symbol_lookup_callback );
104- else
105- * ctx = LLVMCreateDisasm (triple , NULL , 0 , NULL , symbol_lookup_callback );
106- LLVMDisposeMessage (triple );
107-
131+ * ctx = p_bpftool_llvm_create_context (arch );
108132 if (!* ctx ) {
109133 p_err ("Failed to create disassembler" );
110134 return -1 ;
@@ -115,7 +139,7 @@ init_context(disasm_ctx_t *ctx, const char *arch,
115139
116140static void destroy_context (disasm_ctx_t * ctx )
117141{
118- LLVMDisposeMessage (* ctx );
142+ p_bpftool_llvm_destroy_context (* ctx );
119143}
120144
121145static int
@@ -125,8 +149,8 @@ disassemble_insn(disasm_ctx_t *ctx, unsigned char *image, ssize_t len, int pc,
125149 char buf [256 ];
126150 int count ;
127151
128- count = LLVMDisasmInstruction (* ctx , image + pc , len - pc , func_ksym + pc ,
129- buf , sizeof (buf ));
152+ count = p_bpftool_llvm_disassemble (* ctx , image , len , pc , func_ksym ,
153+ buf , sizeof (buf ));
130154 if (json_output )
131155 printf_json (buf );
132156 else
@@ -137,10 +161,10 @@ disassemble_insn(disasm_ctx_t *ctx, unsigned char *image, ssize_t len, int pc,
137161
138162int disasm_init (void )
139163{
140- LLVMInitializeAllTargetInfos ();
141- LLVMInitializeAllTargetMCs () ;
142- LLVMInitializeAllDisassemblers ();
143- return 0 ;
164+ if ( load_llvm_plugin ())
165+ return -1 ;
166+
167+ return p_bpftool_llvm_init () ;
144168}
145169#endif /* HAVE_LLVM_SUPPORT */
146170
0 commit comments