1 // SPDX-License-Identifier: Unlicense
2 /* based on example code: https://github.com/sheredom/llvm_bc_parsing_example
3 * which came under the above (un-)license. does not depend on any FRR
4 * pieces, so no reason to change the license.
6 * please note that while included in the FRR sources, this tool is in no way
7 * supported or maintained by the FRR community. it is provided as a
8 * "convenience"; while it worked at some point (using LLVM 8 / 9), it may
9 * easily break with a future LLVM version or any other factors.
11 * 2020-05-04, David Lamparter
23 #include <llvm-c/BitReader.h>
24 #include <llvm-c/BitWriter.h>
25 #include <llvm-c/Core.h>
27 #include <json-c/json.h>
29 #include "frr-llvm-debuginfo.h"
31 /* if you want to use this without the special FRRouting defines,
32 * remove the following #define
36 static struct dbginfo
*dbginfo
;
38 static void dbgloc_add(struct json_object
*jsobj
, LLVMValueRef obj
)
40 unsigned file_len
= 0;
41 const char *file
= LLVMGetDebugLocFilename(obj
, &file_len
);
42 unsigned line
= LLVMGetDebugLocLine(obj
);
45 file
= "???", file_len
= 3;
46 else if (file
[0] == '.' && file
[1] == '/')
47 file
+= 2, file_len
-= 2;
49 json_object_object_add(jsobj
, "filename",
50 json_object_new_string_len(file
, file_len
));
51 json_object_object_add(jsobj
, "line", json_object_new_int64(line
));
54 static struct json_object
*js_get_or_make(struct json_object
*parent
,
56 struct json_object
*(*maker
)(void))
58 struct json_object
*ret
;
60 ret
= json_object_object_get(parent
, key
);
64 json_object_object_add(parent
, key
, ret
);
68 static bool try_struct_fptr(struct json_object
*js_call
, LLVMValueRef gep
,
71 unsigned long long val
= 0;
73 LLVMTypeRef ptrtype
= LLVMTypeOf(LLVMGetOperand(gep
, 0));
76 /* middle steps like struct a -> struct b a_member; -> fptr */
77 for (int i
= 1; ptrtype
&& i
< LLVMGetNumOperands(gep
) - 1; i
++) {
78 if (LLVMGetTypeKind(ptrtype
) == LLVMPointerTypeKind
79 || LLVMGetTypeKind(ptrtype
) == LLVMArrayTypeKind
80 || LLVMGetTypeKind(ptrtype
) == LLVMVectorTypeKind
) {
81 ptrtype
= LLVMGetElementType(ptrtype
);
85 if (LLVMGetTypeKind(ptrtype
) != LLVMStructTypeKind
)
88 idx
= LLVMGetOperand(gep
, i
);
89 if (!LLVMIsConstant(idx
))
91 val
= LLVMConstIntGetZExtValue(idx
);
93 unsigned n
= LLVMGetNumContainedTypes(ptrtype
);
99 LLVMGetSubtypes(ptrtype
, arr
);
106 idx
= LLVMGetOperand(gep
, LLVMGetNumOperands(gep
) - 1);
107 if (!LLVMIsConstant(idx
))
110 val
= LLVMConstIntGetZExtValue(idx
);
112 char *sname
= NULL
, *mname
= NULL
;
114 if (dbginfo_struct_member(dbginfo
, ptrtype
, val
, &sname
, &mname
)) {
115 fprintf(stderr
, "%s: call to struct %s->%s\n", prefix
, sname
,
118 json_object_object_add(js_call
, "type",
119 json_object_new_string("struct_memb"));
120 json_object_object_add(js_call
, "struct",
121 json_object_new_string(sname
));
122 json_object_object_add(js_call
, "member",
123 json_object_new_string(mname
));
132 static bool details_fptr_vars
= false;
133 static bool details_fptr_consts
= true;
142 static void walk_const_fptrs(struct json_object
*js_call
, LLVMValueRef value
,
143 const char *prefix
, bool *hdr_written
)
148 if (LLVMIsAGlobalVariable(value
)) {
149 type
= LLVMGlobalGetValueType(value
);
150 value
= LLVMGetInitializer(value
);
152 type
= LLVMTypeOf(value
);
155 if (LLVMIsAFunction(value
)) {
156 struct json_object
*js_fptrs
;
158 js_fptrs
= js_get_or_make(js_call
, "funcptrs",
159 json_object_new_array
);
162 const char *fn_name
= LLVMGetValueName2(value
, &fn_len
);
164 size_t curlen
= json_object_array_length(js_fptrs
);
165 struct json_object
*jsobj
;
168 for (size_t i
= 0; i
< curlen
; i
++) {
169 jsobj
= json_object_array_get_idx(js_fptrs
, i
);
170 s
= json_object_get_string(jsobj
);
172 if (s
&& !strcmp(s
, fn_name
))
176 if (details_fptr_consts
&& !*hdr_written
) {
178 "%s: calls function pointer from constant or global data\n",
182 if (details_fptr_consts
)
183 fprintf(stderr
, "%s- constant: %.*s()\n",
184 prefix
, (int)fn_len
, fn_name
);
186 json_object_array_add(js_fptrs
,
187 json_object_new_string_len(fn_name
,
192 kind
= LLVMGetValueKind(value
);
198 case LLVMUndefValueValueKind
:
199 case LLVMConstantAggregateZeroValueKind
:
200 case LLVMConstantPointerNullValueKind
:
201 /* null pointer / array - ignore */
204 case LLVMConstantIntValueKind
:
205 /* integer - ignore */
208 case LLVMConstantStructValueKind
:
209 len
= LLVMCountStructElementTypes(type
);
210 for (unsigned i
= 0; i
< len
; i
++)
211 walk_const_fptrs(js_call
, LLVMGetOperand(value
, i
),
212 prefix
, hdr_written
);
215 case LLVMConstantArrayValueKind
:
216 len
= LLVMGetArrayLength(type
);
217 for (unsigned i
= 0; i
< len
; i
++)
218 walk_const_fptrs(js_call
, LLVMGetOperand(value
, i
),
219 prefix
, hdr_written
);
222 case LLVMConstantExprValueKind
:
223 switch (LLVMGetConstOpcode(value
)) {
224 case LLVMGetElementPtr
:
225 if (try_struct_fptr(js_call
, value
, prefix
)) {
231 "%s: calls function pointer from unhandled const GEP\n",
236 /* to help the user / development */
239 "%s: calls function pointer from constexpr\n",
243 dump
= LLVMPrintValueToString(value
);
244 fprintf(stderr
, "%s- [opcode=%d] %s\n", prefix
,
245 LLVMGetConstOpcode(value
), dump
);
246 LLVMDisposeMessage(dump
);
251 /* to help the user / development */
254 "%s: calls function pointer from constant or global data\n",
258 dump
= LLVMPrintValueToString(value
);
260 "%s- value could not be processed:\n"
261 "%s- [kind=%d] %s\n",
262 prefix
, prefix
, kind
, dump
);
263 LLVMDisposeMessage(dump
);
270 static bool is_thread_sched(const char *name
, size_t len
)
272 #define thread_prefix "_"
273 static const char *const names
[] = {
274 thread_prefix
"event_add_read_write",
275 thread_prefix
"event_add_timer",
276 thread_prefix
"event_add_timer_msec",
277 thread_prefix
"event_add_timer_tv",
278 thread_prefix
"event_add_event",
279 thread_prefix
"event_execute",
283 for (i
= 0; i
< sizeof(names
) / sizeof(names
[0]); i
++) {
284 if (strlen(names
[i
]) != len
)
286 if (!memcmp(names
[i
], name
, len
))
293 static bool _check_val(bool cond
, const char *text
, LLVMValueRef dumpval
)
298 char *dump
= LLVMPrintValueToString(dumpval
);
299 fprintf(stderr
, "check failed: %s\ndump:\n\t%s\n", text
, dump
);
300 LLVMDisposeMessage(dump
);
304 #define check_val(cond, dump) \
305 if (!_check_val(cond, #cond, dump)) \
308 static char *get_string(LLVMValueRef value
)
310 if (!LLVMIsAConstant(value
))
311 return strdup("!NOT-A-CONST");
313 if (LLVMGetValueKind(value
) == LLVMConstantExprValueKind
314 && LLVMGetConstOpcode(value
) == LLVMGetElementPtr
) {
315 value
= LLVMGetOperand(value
, 0);
317 if (!LLVMIsAConstant(value
))
318 return strdup("!NOT-A-CONST-2");
321 if (LLVMIsAGlobalVariable(value
))
322 value
= LLVMGetInitializer(value
);
325 const char *sval
= LLVMGetAsString(value
, &len
);
327 return strndup(sval
, len
);
330 static void handle_yang_module(struct json_object
*js_special
,
331 LLVMValueRef yang_mod
)
333 check_val(LLVMIsAGlobalVariable(yang_mod
), yang_mod
);
337 value
= LLVMGetInitializer(yang_mod
);
338 LLVMValueKind kind
= LLVMGetValueKind(value
);
340 check_val(kind
== LLVMConstantStructValueKind
, value
);
343 const char *var_name
= LLVMGetValueName2(yang_mod
, &var_len
);
344 char buf_name
[var_len
+ 1];
346 memcpy(buf_name
, var_name
, var_len
);
347 buf_name
[var_len
] = '\0';
349 struct json_object
*js_yang
, *js_yangmod
, *js_items
;
351 js_yang
= js_get_or_make(js_special
, "yang", json_object_new_object
);
352 js_yangmod
= js_get_or_make(js_yang
, buf_name
, json_object_new_object
);
353 js_items
= js_get_or_make(js_yangmod
, "items", json_object_new_array
);
355 char *mod_name
= get_string(LLVMGetOperand(value
, 0));
356 json_object_object_add(js_yangmod
, "name",
357 json_object_new_string(mod_name
));
360 value
= LLVMGetOperand(value
, 1);
361 kind
= LLVMGetValueKind(value
);
362 check_val(kind
== LLVMConstantArrayValueKind
, value
);
364 unsigned len
= LLVMGetArrayLength(LLVMTypeOf(value
));
366 for (unsigned i
= 0; i
< len
- 1; i
++) {
367 struct json_object
*js_item
, *js_cbs
;
368 LLVMValueRef item
= LLVMGetOperand(value
, i
);
369 char *xpath
= get_string(LLVMGetOperand(item
, 0));
371 js_item
= json_object_new_object();
372 json_object_array_add(js_items
, js_item
);
374 json_object_object_add(js_item
, "xpath",
375 json_object_new_string(xpath
));
376 js_cbs
= js_get_or_make(js_item
, "cbs", json_object_new_object
);
380 LLVMValueRef cbs
= LLVMGetOperand(item
, 1);
382 check_val(LLVMGetValueKind(cbs
) == LLVMConstantStructValueKind
,
385 LLVMTypeRef cbs_type
= LLVMTypeOf(cbs
);
386 unsigned cblen
= LLVMCountStructElementTypes(cbs_type
);
388 for (unsigned i
= 0; i
< cblen
; i
++) {
389 LLVMValueRef cb
= LLVMGetOperand(cbs
, i
);
394 if (dbginfo_struct_member(dbginfo
, cbs_type
, i
, &sname
,
399 if (LLVMIsAFunction(cb
)) {
403 fn_name
= LLVMGetValueName2(cb
, &fn_len
);
405 json_object_object_add(
407 json_object_new_string_len(fn_name
,
417 static void handle_daemoninfo(struct json_object
*js_special
,
418 LLVMValueRef daemoninfo
)
420 check_val(LLVMIsAGlobalVariable(daemoninfo
), daemoninfo
);
426 type
= LLVMGlobalGetValueType(daemoninfo
);
427 value
= LLVMGetInitializer(daemoninfo
);
428 LLVMValueKind kind
= LLVMGetValueKind(value
);
430 check_val(kind
== LLVMConstantStructValueKind
, value
);
434 len
= LLVMCountStructElementTypes(type
);
436 LLVMTypeRef fieldtypes
[len
];
437 LLVMGetSubtypes(type
, fieldtypes
);
439 for (unsigned i
= 0; i
< len
; i
++) {
440 LLVMTypeRef t
= fieldtypes
[i
];
442 if (LLVMGetTypeKind(t
) != LLVMPointerTypeKind
)
444 t
= LLVMGetElementType(t
);
445 if (LLVMGetTypeKind(t
) != LLVMPointerTypeKind
)
447 t
= LLVMGetElementType(t
);
448 if (LLVMGetTypeKind(t
) != LLVMStructTypeKind
)
451 const char *name
= LLVMGetStructName(t
);
452 if (!strcmp(name
, "struct.frr_yang_module_info"))
459 LLVMValueRef yang_mods
= LLVMGetOperand(value
, yang_idx
);
460 LLVMValueRef yang_size
= LLVMGetOperand(value
, yang_idx
+ 1);
462 check_val(LLVMIsConstant(yang_size
), yang_size
);
464 unsigned long long ival
= LLVMConstIntGetZExtValue(yang_size
);
466 check_val(LLVMGetValueKind(yang_mods
) == LLVMConstantExprValueKind
467 && LLVMGetConstOpcode(yang_mods
) == LLVMGetElementPtr
,
470 yang_mods
= LLVMGetOperand(yang_mods
, 0);
472 check_val(LLVMIsAGlobalVariable(yang_mods
), yang_mods
);
474 yang_mods
= LLVMGetInitializer(yang_mods
);
476 check_val(LLVMGetValueKind(yang_mods
) == LLVMConstantArrayValueKind
,
479 len
= LLVMGetArrayLength(LLVMTypeOf(yang_mods
));
482 fprintf(stderr
, "length mismatch - %llu vs. %u\n", ival
, len
);
484 for (unsigned i
= 0; i
< len
; i
++) {
487 LLVMValueRef item
= LLVMGetOperand(yang_mods
, i
);
488 LLVMValueKind kind
= LLVMGetValueKind(item
);
490 check_val(kind
== LLVMGlobalVariableValueKind
491 || kind
== LLVMConstantExprValueKind
,
494 if (kind
== LLVMGlobalVariableValueKind
)
497 LLVMOpcode opcode
= LLVMGetConstOpcode(item
);
500 item
= LLVMGetOperand(item
, 0);
501 handle_yang_module(js_special
, item
);
505 dump
= LLVMPrintValueToString(item
);
506 printf("[%u] = [opcode=%u] %s\n", i
, opcode
, dump
);
507 LLVMDisposeMessage(dump
);
512 static void process_call(struct json_object
*js_calls
,
513 struct json_object
*js_special
,
515 LLVMValueRef function
)
517 struct json_object
*js_call
, *js_fptrs
= NULL
;
519 LLVMValueRef called
= LLVMGetCalledValue(instr
);
521 if (LLVMIsAInlineAsm(called
))
524 if (LLVMIsAConstantExpr(called
)) {
525 LLVMOpcode opcode
= LLVMGetConstOpcode(called
);
527 if (opcode
== LLVMBitCast
) {
528 LLVMValueRef op0
= LLVMGetOperand(called
, 0);
530 if (LLVMIsAFunction(op0
))
535 size_t called_len
= 0;
536 const char *called_name
= LLVMGetValueName2(called
, &called_len
);
537 unsigned n_args
= LLVMGetNumArgOperands(instr
);
539 bool is_external
= LLVMIsDeclaration(called
);
541 js_call
= json_object_new_object();
542 json_object_array_add(js_calls
, js_call
);
543 dbgloc_add(js_call
, instr
);
544 json_object_object_add(js_call
, "is_external",
545 json_object_new_boolean(is_external
));
547 if (!called_name
|| called_len
== 0) {
548 json_object_object_add(js_call
, "type",
549 json_object_new_string("indirect"));
551 LLVMValueRef last
= called
;
554 const char *name_c
= LLVMGetValueName2(function
, &name_len
);
557 /* information for FRR hooks is dumped for the registration
558 * in _hook_typecheck; we can safely ignore the funcptr here
560 if (strncmp(name_c
, "hook_call_", 10) == 0)
564 unsigned file_len
= 0;
565 const char *file
= LLVMGetDebugLocFilename(instr
, &file_len
);
566 unsigned line
= LLVMGetDebugLocLine(instr
);
569 snprintf(prefix
, sizeof(prefix
), "%.*s:%d:%.*s()",
570 (int)file_len
, file
, line
, (int)name_len
, name_c
);
572 if (LLVMIsALoadInst(called
)
573 && LLVMIsAGetElementPtrInst(LLVMGetOperand(called
, 0))
574 && try_struct_fptr(js_call
, LLVMGetOperand(called
, 0),
576 goto out_struct_fptr
;
578 while (LLVMIsALoadInst(last
) || LLVMIsAGetElementPtrInst(last
))
579 /* skipping over details for GEP here, but meh. */
580 last
= LLVMGetOperand(last
, 0);
582 if (LLVMIsAAllocaInst(last
)) {
583 /* "alloca" is just generically all variables on the
584 * stack, this does not refer to C alloca() calls
586 * looking at the control flow in the function can
587 * give better results here, it's just not implemented
591 "%s: call to a function pointer variable\n",
594 if (details_fptr_vars
) {
595 char *dump
= LLVMPrintValueToString(called
);
596 printf("%s- %s\n", prefix
, dump
);
597 LLVMDisposeMessage(dump
);
600 json_object_object_add(
602 json_object_new_string("stack_fptr"));
603 } else if (LLVMIsACallInst(last
)) {
604 /* calling the a function pointer returned from
607 struct json_object
*js_indirect
;
609 js_indirect
= js_get_or_make(js_call
, "return_of",
610 json_object_new_array
);
612 process_call(js_indirect
, js_special
, last
, function
);
613 } else if (LLVMIsAConstant(last
)) {
614 /* function pointer is a constant (includes loading
615 * from complicated constants like structs or arrays.)
617 bool hdr_written
= false;
618 walk_const_fptrs(js_call
, last
, prefix
, &hdr_written
);
619 if (details_fptr_consts
&& !hdr_written
)
621 "%s: calls function pointer from constant or global data, but no non-NULL function pointers found\n",
624 char *dump
= LLVMPrintValueToString(called
);
625 fprintf(stderr
, "%s: ??? %s\n", prefix
, dump
);
626 LLVMDisposeMessage(dump
);
629 } else if (!strcmp(called_name
, "_install_element")) {
630 LLVMValueRef param0
= LLVMGetOperand(instr
, 0);
631 if (!LLVMIsAConstantInt(param0
))
634 long long vty_node
= LLVMConstIntGetSExtValue(param0
);
635 json_object_object_add(js_call
, "vty_node",
636 json_object_new_int64(vty_node
));
638 LLVMValueRef param1
= LLVMGetOperand(instr
, 1);
639 if (!LLVMIsAGlobalVariable(param1
))
642 LLVMValueRef intlz
= LLVMGetInitializer(param1
);
643 assert(intlz
&& LLVMIsConstant(intlz
));
645 LLVMValueKind intlzkind
= LLVMGetValueKind(intlz
);
646 assert(intlzkind
== LLVMConstantStructValueKind
);
648 LLVMValueRef funcptr
= LLVMGetOperand(intlz
, 4);
649 assert(LLVMIsAFunction(funcptr
));
651 size_t target_len
= 0;
653 target
= LLVMGetValueName2(funcptr
, &target_len
);
655 json_object_object_add(
657 json_object_new_string("install_element"));
658 json_object_object_add(
660 json_object_new_string_len(target
, target_len
));
664 json_object_object_add(
666 json_object_new_string("install_element"));
668 } else if (is_thread_sched(called_name
, called_len
)) {
669 json_object_object_add(js_call
, "type",
670 json_object_new_string("thread_sched"));
671 json_object_object_add(
673 json_object_new_string_len(called_name
, called_len
));
676 fparam
= LLVMGetOperand(instr
, 2);
679 size_t target_len
= 0;
681 target
= LLVMGetValueName2(fparam
, &target_len
);
683 json_object_object_add(js_call
, "target",
685 json_object_new_string_len(target
, target_len
));
686 if (!LLVMIsAFunction(fparam
))
687 json_object_object_add(js_call
, "target_unresolved",
688 json_object_new_boolean(true));
690 } else if (!strncmp(called_name
, "_hook_typecheck_",
691 strlen("_hook_typecheck_"))) {
692 struct json_object
*js_hook
, *js_this
;
693 const char *hook_name
;
695 hook_name
= called_name
+ strlen("_hook_typecheck_");
697 json_object_object_add(js_call
, "type",
698 json_object_new_string("hook"));
700 LLVMValueRef param0
= LLVMGetOperand(instr
, 0);
701 if (!LLVMIsAFunction(param0
))
704 size_t target_len
= 0;
706 target
= LLVMGetValueName2(param0
, &target_len
);
708 js_hook
= js_get_or_make(js_special
, "hooks",
709 json_object_new_object
);
710 js_hook
= js_get_or_make(js_hook
, hook_name
,
711 json_object_new_array
);
713 js_this
= json_object_new_object();
714 json_object_array_add(js_hook
, js_this
);
716 dbgloc_add(js_this
, instr
);
717 json_object_object_add(
719 json_object_new_string_len(target
, target_len
));
722 /* TODO (FRR specifics):
723 * - workqueues - not sure we can do much there
726 #endif /* FRR_SPECIFIC */
727 } else if (!strcmp(called_name
, "frr_preinit")) {
728 LLVMValueRef daemoninfo
= LLVMGetOperand(instr
, 0);
730 handle_daemoninfo(js_special
, daemoninfo
);
732 json_object_object_add(
734 json_object_new_string_len(called_name
, called_len
));
736 json_object_object_add(
738 json_object_new_string_len(called_name
, called_len
));
742 for (unsigned argno
= 0; argno
< n_args
; argno
++) {
743 LLVMValueRef param
= LLVMGetOperand(instr
, argno
);
745 const char *target_name
;
747 if (LLVMIsAFunction(param
)) {
748 js_fptrs
= js_get_or_make(js_call
, "funcptrs",
749 json_object_new_array
);
751 target_name
= LLVMGetValueName2(param
, &target_len
);
753 json_object_array_add(js_fptrs
,
754 json_object_new_string_len(
755 target_name
, target_len
));
760 static void process_fn(struct json_object
*funcs
,
761 struct json_object
*js_special
,
762 LLVMValueRef function
)
764 struct json_object
*js_func
, *js_calls
;
767 const char *name_c
= LLVMGetValueName2(function
, &name_len
);
770 name
= strndup(name_c
, name_len
);
772 js_func
= json_object_object_get(funcs
, name
);
774 unsigned file_len
= 0;
775 const char *file
= LLVMGetDebugLocFilename(function
, &file_len
);
776 unsigned line
= LLVMGetDebugLocLine(function
);
778 fprintf(stderr
, "%.*s:%d:%s(): duplicate definition!\n",
779 (int)file_len
, file
, line
, name
);
784 js_func
= json_object_new_object();
785 json_object_object_add(funcs
, name
, js_func
);
788 js_calls
= json_object_new_array();
789 json_object_object_add(js_func
, "calls", js_calls
);
791 dbgloc_add(js_func
, function
);
793 for (LLVMBasicBlockRef basicBlock
= LLVMGetFirstBasicBlock(function
);
794 basicBlock
; basicBlock
= LLVMGetNextBasicBlock(basicBlock
)) {
796 for (LLVMValueRef instr
= LLVMGetFirstInstruction(basicBlock
);
797 instr
; instr
= LLVMGetNextInstruction(instr
)) {
799 if (LLVMIsAIntrinsicInst(instr
))
802 if (LLVMIsACallInst(instr
) || LLVMIsAInvokeInst(instr
))
803 process_call(js_calls
, js_special
, instr
,
809 static void help(int retcode
)
812 "FRR LLVM bitcode to callgraph analyzer\n"
814 "usage: frr-llvm-cg [-q|-v] [-o <JSONOUTPUT>] BITCODEINPUT\n"
816 "\t-o FILENAME\twrite JSON output to file instead of stdout\n"
817 "\t-v\t\tbe more verbose\n"
820 "BITCODEINPUT must be a LLVM binary bitcode file (not text\n"
821 "representation.) Use - to read from stdin.\n"
823 "Note it may be necessary to build this binary tool against\n"
824 "the specific LLVM version that created the bitcode file.\n");
828 int main(int argc
, char **argv
)
831 const char *out
= NULL
;
832 const char *inp
= NULL
;
835 while ((opt
= getopt(argc
, argv
, "hvqo:")) != -1) {
843 if (v_or_q
&& v_or_q
!= 'v')
845 details_fptr_vars
= true;
846 details_fptr_consts
= true;
850 if (v_or_q
&& v_or_q
!= 'q')
852 details_fptr_vars
= false;
853 details_fptr_consts
= false;
864 if (optind
!= argc
- 1)
869 LLVMMemoryBufferRef memoryBuffer
;
873 // check if we are to read our input file from stdin
874 if (!strcmp(inp
, "-")) {
876 ret
= LLVMCreateMemoryBufferWithSTDIN(&memoryBuffer
, &message
);
878 ret
= LLVMCreateMemoryBufferWithContentsOfFile(
879 inp
, &memoryBuffer
, &message
);
883 fprintf(stderr
, "failed to open %s: %s\n", inp
, message
);
888 // now create our module using the memorybuffer
889 LLVMModuleRef module
;
890 if (LLVMParseBitcode2(memoryBuffer
, &module
)) {
891 fprintf(stderr
, "%s: invalid bitcode\n", inp
);
892 LLVMDisposeMemoryBuffer(memoryBuffer
);
896 // done with the memory buffer now, so dispose of it
897 LLVMDisposeMemoryBuffer(memoryBuffer
);
899 dbginfo
= dbginfo_load(module
);
901 struct json_object
*js_root
, *js_funcs
, *js_special
;
903 js_root
= json_object_new_object();
904 js_funcs
= json_object_new_object();
905 json_object_object_add(js_root
, "functions", js_funcs
);
906 js_special
= json_object_new_object();
907 json_object_object_add(js_root
, "special", js_special
);
909 // loop through all the functions in the module
910 for (LLVMValueRef function
= LLVMGetFirstFunction(module
); function
;
911 function
= LLVMGetNextFunction(function
)) {
912 if (LLVMIsDeclaration(function
))
915 process_fn(js_funcs
, js_special
, function
);
919 char tmpout
[strlen(out
) + 5];
921 snprintf(tmpout
, sizeof(tmpout
), "%s.tmp", out
);
922 ret
= json_object_to_file_ext(tmpout
, js_root
,
923 JSON_C_TO_STRING_PRETTY
|
924 JSON_C_TO_STRING_PRETTY_TAB
|
925 JSON_C_TO_STRING_NOSLASHESCAPE
);
927 fprintf(stderr
, "could not write JSON to file\n");
930 if (rename(tmpout
, out
)) {
931 fprintf(stderr
, "could not rename JSON output: %s\n",
937 ret
= json_object_to_fd(1, js_root
,
938 JSON_C_TO_STRING_PRETTY
|
939 JSON_C_TO_STRING_PRETTY_TAB
|
940 JSON_C_TO_STRING_NOSLASHESCAPE
);
942 fprintf(stderr
, "could not write JSON to stdout\n");
947 LLVMDisposeModule(module
);