1 // This is free and unencumbered software released into the public domain.
3 // Anyone is free to copy, modify, publish, use, compile, sell, or
4 // distribute this software, either in source code form or as a compiled
5 // binary, for any purpose, commercial or non-commercial, and by any
8 // In jurisdictions that recognize copyright laws, the author or authors
9 // of this software dedicate any and all copyright interest in the
10 // software to the public domain. We make this dedication for the benefit
11 // of the public at large and to the detriment of our heirs and
12 // successors. We intend this dedication to be an overt act of
13 // relinquishment in perpetuity of all present and future rights to this
14 // software under copyright law.
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19 // IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 // OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 // OTHER DEALINGS IN THE SOFTWARE.
24 // For more information, please refer to <http://unlicense.org/>
26 /* based on example code: https://github.com/sheredom/llvm_bc_parsing_example
27 * which came under the above (un-)license. does not depend on any FRR
28 * pieces, so no reason to change the license.
30 * please note that while included in the FRR sources, this tool is in no way
31 * supported or maintained by the FRR community. it is provided as a
32 * "convenience"; while it worked at some point (using LLVM 8 / 9), it may
33 * easily break with a future LLVM version or any other factors.
35 * 2020-05-04, David Lamparter
47 #include <llvm-c/BitReader.h>
48 #include <llvm-c/BitWriter.h>
49 #include <llvm-c/Core.h>
51 #include <json-c/json.h>
53 #include "frr-llvm-debuginfo.h"
55 /* if you want to use this without the special FRRouting defines,
56 * remove the following #define
60 static struct dbginfo
*dbginfo
;
62 static void dbgloc_add(struct json_object
*jsobj
, LLVMValueRef obj
)
64 unsigned file_len
= 0;
65 const char *file
= LLVMGetDebugLocFilename(obj
, &file_len
);
66 unsigned line
= LLVMGetDebugLocLine(obj
);
69 file
= "???", file_len
= 3;
70 else if (file
[0] == '.' && file
[1] == '/')
71 file
+= 2, file_len
-= 2;
73 json_object_object_add(jsobj
, "filename",
74 json_object_new_string_len(file
, file_len
));
75 json_object_object_add(jsobj
, "line", json_object_new_int64(line
));
78 static struct json_object
*js_get_or_make(struct json_object
*parent
,
80 struct json_object
*(*maker
)(void))
82 struct json_object
*ret
;
84 ret
= json_object_object_get(parent
, key
);
88 json_object_object_add(parent
, key
, ret
);
92 static bool try_struct_fptr(struct json_object
*js_call
, LLVMValueRef gep
,
95 unsigned long long val
= 0;
97 LLVMTypeRef ptrtype
= LLVMTypeOf(LLVMGetOperand(gep
, 0));
100 /* middle steps like struct a -> struct b a_member; -> fptr */
101 for (int i
= 1; ptrtype
&& i
< LLVMGetNumOperands(gep
) - 1; i
++) {
102 if (LLVMGetTypeKind(ptrtype
) == LLVMPointerTypeKind
103 || LLVMGetTypeKind(ptrtype
) == LLVMArrayTypeKind
104 || LLVMGetTypeKind(ptrtype
) == LLVMVectorTypeKind
) {
105 ptrtype
= LLVMGetElementType(ptrtype
);
109 if (LLVMGetTypeKind(ptrtype
) != LLVMStructTypeKind
)
112 idx
= LLVMGetOperand(gep
, i
);
113 if (!LLVMIsConstant(idx
))
115 val
= LLVMConstIntGetZExtValue(idx
);
117 unsigned n
= LLVMGetNumContainedTypes(ptrtype
);
123 LLVMGetSubtypes(ptrtype
, arr
);
130 idx
= LLVMGetOperand(gep
, LLVMGetNumOperands(gep
) - 1);
131 if (!LLVMIsConstant(idx
))
134 val
= LLVMConstIntGetZExtValue(idx
);
136 char *sname
= NULL
, *mname
= NULL
;
138 if (dbginfo_struct_member(dbginfo
, ptrtype
, val
, &sname
, &mname
)) {
139 fprintf(stderr
, "%s: call to struct %s->%s\n", prefix
, sname
,
142 json_object_object_add(js_call
, "type",
143 json_object_new_string("struct_memb"));
144 json_object_object_add(js_call
, "struct",
145 json_object_new_string(sname
));
146 json_object_object_add(js_call
, "member",
147 json_object_new_string(mname
));
156 static bool details_fptr_vars
= false;
157 static bool details_fptr_consts
= true;
166 static void walk_const_fptrs(struct json_object
*js_call
, LLVMValueRef value
,
167 const char *prefix
, bool *hdr_written
)
172 if (LLVMIsAGlobalVariable(value
)) {
173 type
= LLVMGlobalGetValueType(value
);
174 value
= LLVMGetInitializer(value
);
176 type
= LLVMTypeOf(value
);
179 if (LLVMIsAFunction(value
)) {
180 struct json_object
*js_fptrs
;
182 js_fptrs
= js_get_or_make(js_call
, "funcptrs",
183 json_object_new_array
);
186 const char *fn_name
= LLVMGetValueName2(value
, &fn_len
);
188 size_t curlen
= json_object_array_length(js_fptrs
);
189 struct json_object
*jsobj
;
192 for (size_t i
= 0; i
< curlen
; i
++) {
193 jsobj
= json_object_array_get_idx(js_fptrs
, i
);
194 s
= json_object_get_string(jsobj
);
196 if (s
&& !strcmp(s
, fn_name
))
200 if (details_fptr_consts
&& !*hdr_written
) {
202 "%s: calls function pointer from constant or global data\n",
206 if (details_fptr_consts
)
207 fprintf(stderr
, "%s- constant: %.*s()\n",
208 prefix
, (int)fn_len
, fn_name
);
210 json_object_array_add(js_fptrs
,
211 json_object_new_string_len(fn_name
,
216 kind
= LLVMGetValueKind(value
);
222 case LLVMUndefValueValueKind
:
223 case LLVMConstantAggregateZeroValueKind
:
224 case LLVMConstantPointerNullValueKind
:
225 /* null pointer / array - ignore */
228 case LLVMConstantIntValueKind
:
229 /* integer - ignore */
232 case LLVMConstantStructValueKind
:
233 len
= LLVMCountStructElementTypes(type
);
234 for (unsigned i
= 0; i
< len
; i
++)
235 walk_const_fptrs(js_call
, LLVMGetOperand(value
, i
),
236 prefix
, hdr_written
);
239 case LLVMConstantArrayValueKind
:
240 len
= LLVMGetArrayLength(type
);
241 for (unsigned i
= 0; i
< len
; i
++)
242 walk_const_fptrs(js_call
, LLVMGetOperand(value
, i
),
243 prefix
, hdr_written
);
246 case LLVMConstantExprValueKind
:
247 switch (LLVMGetConstOpcode(value
)) {
248 case LLVMGetElementPtr
:
249 if (try_struct_fptr(js_call
, value
, prefix
)) {
255 "%s: calls function pointer from unhandled const GEP\n",
260 /* to help the user / development */
263 "%s: calls function pointer from constexpr\n",
267 dump
= LLVMPrintValueToString(value
);
268 fprintf(stderr
, "%s- [opcode=%d] %s\n", prefix
,
269 LLVMGetConstOpcode(value
), dump
);
270 LLVMDisposeMessage(dump
);
275 /* to help the user / development */
278 "%s: calls function pointer from constant or global data\n",
282 dump
= LLVMPrintValueToString(value
);
284 "%s- value could not be processed:\n"
285 "%s- [kind=%d] %s\n",
286 prefix
, prefix
, kind
, dump
);
287 LLVMDisposeMessage(dump
);
294 static bool is_thread_sched(const char *name
, size_t len
)
296 #define thread_prefix "_"
297 static const char *const names
[] = {
298 thread_prefix
"thread_add_read_write",
299 thread_prefix
"thread_add_timer",
300 thread_prefix
"thread_add_timer_msec",
301 thread_prefix
"thread_add_timer_tv",
302 thread_prefix
"thread_add_event",
303 thread_prefix
"thread_execute",
307 for (i
= 0; i
< sizeof(names
) / sizeof(names
[0]); i
++) {
308 if (strlen(names
[i
]) != len
)
310 if (!memcmp(names
[i
], name
, len
))
317 static bool _check_val(bool cond
, const char *text
, LLVMValueRef dumpval
)
322 char *dump
= LLVMPrintValueToString(dumpval
);
323 fprintf(stderr
, "check failed: %s\ndump:\n\t%s\n", text
, dump
);
324 LLVMDisposeMessage(dump
);
328 #define check_val(cond, dump) \
329 if (!_check_val(cond, #cond, dump)) \
332 static char *get_string(LLVMValueRef value
)
334 if (!LLVMIsAConstant(value
))
335 return strdup("!NOT-A-CONST");
337 if (LLVMGetValueKind(value
) == LLVMConstantExprValueKind
338 && LLVMGetConstOpcode(value
) == LLVMGetElementPtr
) {
339 value
= LLVMGetOperand(value
, 0);
341 if (!LLVMIsAConstant(value
))
342 return strdup("!NOT-A-CONST-2");
345 if (LLVMIsAGlobalVariable(value
))
346 value
= LLVMGetInitializer(value
);
349 const char *sval
= LLVMGetAsString(value
, &len
);
351 return strndup(sval
, len
);
354 static void handle_yang_module(struct json_object
*js_special
,
355 LLVMValueRef yang_mod
)
357 check_val(LLVMIsAGlobalVariable(yang_mod
), yang_mod
);
361 value
= LLVMGetInitializer(yang_mod
);
362 LLVMValueKind kind
= LLVMGetValueKind(value
);
364 check_val(kind
== LLVMConstantStructValueKind
, value
);
367 const char *var_name
= LLVMGetValueName2(yang_mod
, &var_len
);
368 char buf_name
[var_len
+ 1];
370 memcpy(buf_name
, var_name
, var_len
);
371 buf_name
[var_len
] = '\0';
373 struct json_object
*js_yang
, *js_yangmod
, *js_items
;
375 js_yang
= js_get_or_make(js_special
, "yang", json_object_new_object
);
376 js_yangmod
= js_get_or_make(js_yang
, buf_name
, json_object_new_object
);
377 js_items
= js_get_or_make(js_yangmod
, "items", json_object_new_array
);
379 char *mod_name
= get_string(LLVMGetOperand(value
, 0));
380 json_object_object_add(js_yangmod
, "name",
381 json_object_new_string(mod_name
));
384 value
= LLVMGetOperand(value
, 1);
385 kind
= LLVMGetValueKind(value
);
386 check_val(kind
== LLVMConstantArrayValueKind
, value
);
388 unsigned len
= LLVMGetArrayLength(LLVMTypeOf(value
));
390 for (unsigned i
= 0; i
< len
- 1; i
++) {
391 struct json_object
*js_item
, *js_cbs
;
392 LLVMValueRef item
= LLVMGetOperand(value
, i
);
393 char *xpath
= get_string(LLVMGetOperand(item
, 0));
395 js_item
= json_object_new_object();
396 json_object_array_add(js_items
, js_item
);
398 json_object_object_add(js_item
, "xpath",
399 json_object_new_string(xpath
));
400 js_cbs
= js_get_or_make(js_item
, "cbs", json_object_new_object
);
404 LLVMValueRef cbs
= LLVMGetOperand(item
, 1);
406 check_val(LLVMGetValueKind(cbs
) == LLVMConstantStructValueKind
,
409 LLVMTypeRef cbs_type
= LLVMTypeOf(cbs
);
410 unsigned cblen
= LLVMCountStructElementTypes(cbs_type
);
412 for (unsigned i
= 0; i
< cblen
; i
++) {
413 LLVMValueRef cb
= LLVMGetOperand(cbs
, i
);
418 if (dbginfo_struct_member(dbginfo
, cbs_type
, i
, &sname
,
423 if (LLVMIsAFunction(cb
)) {
427 fn_name
= LLVMGetValueName2(cb
, &fn_len
);
429 json_object_object_add(
431 json_object_new_string_len(fn_name
,
441 static void handle_daemoninfo(struct json_object
*js_special
,
442 LLVMValueRef daemoninfo
)
444 check_val(LLVMIsAGlobalVariable(daemoninfo
), daemoninfo
);
450 type
= LLVMGlobalGetValueType(daemoninfo
);
451 value
= LLVMGetInitializer(daemoninfo
);
452 LLVMValueKind kind
= LLVMGetValueKind(value
);
454 check_val(kind
== LLVMConstantStructValueKind
, value
);
458 len
= LLVMCountStructElementTypes(type
);
460 LLVMTypeRef fieldtypes
[len
];
461 LLVMGetSubtypes(type
, fieldtypes
);
463 for (unsigned i
= 0; i
< len
; i
++) {
464 LLVMTypeRef t
= fieldtypes
[i
];
466 if (LLVMGetTypeKind(t
) != LLVMPointerTypeKind
)
468 t
= LLVMGetElementType(t
);
469 if (LLVMGetTypeKind(t
) != LLVMPointerTypeKind
)
471 t
= LLVMGetElementType(t
);
472 if (LLVMGetTypeKind(t
) != LLVMStructTypeKind
)
475 const char *name
= LLVMGetStructName(t
);
476 if (!strcmp(name
, "struct.frr_yang_module_info"))
483 LLVMValueRef yang_mods
= LLVMGetOperand(value
, yang_idx
);
484 LLVMValueRef yang_size
= LLVMGetOperand(value
, yang_idx
+ 1);
486 check_val(LLVMIsConstant(yang_size
), yang_size
);
488 unsigned long long ival
= LLVMConstIntGetZExtValue(yang_size
);
490 check_val(LLVMGetValueKind(yang_mods
) == LLVMConstantExprValueKind
491 && LLVMGetConstOpcode(yang_mods
) == LLVMGetElementPtr
,
494 yang_mods
= LLVMGetOperand(yang_mods
, 0);
496 check_val(LLVMIsAGlobalVariable(yang_mods
), yang_mods
);
498 yang_mods
= LLVMGetInitializer(yang_mods
);
500 check_val(LLVMGetValueKind(yang_mods
) == LLVMConstantArrayValueKind
,
503 len
= LLVMGetArrayLength(LLVMTypeOf(yang_mods
));
506 fprintf(stderr
, "length mismatch - %llu vs. %u\n", ival
, len
);
508 for (unsigned i
= 0; i
< len
; i
++) {
511 LLVMValueRef item
= LLVMGetOperand(yang_mods
, i
);
512 LLVMValueKind kind
= LLVMGetValueKind(item
);
514 check_val(kind
== LLVMGlobalVariableValueKind
515 || kind
== LLVMConstantExprValueKind
,
518 if (kind
== LLVMGlobalVariableValueKind
)
521 LLVMOpcode opcode
= LLVMGetConstOpcode(item
);
524 item
= LLVMGetOperand(item
, 0);
525 handle_yang_module(js_special
, item
);
529 dump
= LLVMPrintValueToString(item
);
530 printf("[%u] = [opcode=%u] %s\n", i
, opcode
, dump
);
531 LLVMDisposeMessage(dump
);
536 static void process_call(struct json_object
*js_calls
,
537 struct json_object
*js_special
,
539 LLVMValueRef function
)
541 struct json_object
*js_call
, *js_fptrs
= NULL
;
543 LLVMValueRef called
= LLVMGetCalledValue(instr
);
545 if (LLVMIsAInlineAsm(called
))
548 if (LLVMIsAConstantExpr(called
)) {
549 LLVMOpcode opcode
= LLVMGetConstOpcode(called
);
551 if (opcode
== LLVMBitCast
) {
552 LLVMValueRef op0
= LLVMGetOperand(called
, 0);
554 if (LLVMIsAFunction(op0
))
559 size_t called_len
= 0;
560 const char *called_name
= LLVMGetValueName2(called
, &called_len
);
561 unsigned n_args
= LLVMGetNumArgOperands(instr
);
563 bool is_external
= LLVMIsDeclaration(called
);
564 enum called_fn called_type
= FN_GENERIC
;
566 js_call
= json_object_new_object();
567 json_object_array_add(js_calls
, js_call
);
568 dbgloc_add(js_call
, instr
);
569 json_object_object_add(js_call
, "is_external",
570 json_object_new_boolean(is_external
));
572 if (!called_name
|| called_len
== 0) {
573 called_type
= FN_NONAME
;
574 json_object_object_add(js_call
, "type",
575 json_object_new_string("indirect"));
577 LLVMValueRef last
= called
;
580 const char *name_c
= LLVMGetValueName2(function
, &name_len
);
583 /* information for FRR hooks is dumped for the registration
584 * in _hook_typecheck; we can safely ignore the funcptr here
586 if (strncmp(name_c
, "hook_call_", 10) == 0)
590 unsigned file_len
= 0;
591 const char *file
= LLVMGetDebugLocFilename(instr
, &file_len
);
592 unsigned line
= LLVMGetDebugLocLine(instr
);
595 snprintf(prefix
, sizeof(prefix
), "%.*s:%d:%.*s()",
596 (int)file_len
, file
, line
, (int)name_len
, name_c
);
598 if (LLVMIsALoadInst(called
)
599 && LLVMIsAGetElementPtrInst(LLVMGetOperand(called
, 0))
600 && try_struct_fptr(js_call
, LLVMGetOperand(called
, 0),
602 goto out_struct_fptr
;
604 while (LLVMIsALoadInst(last
) || LLVMIsAGetElementPtrInst(last
))
605 /* skipping over details for GEP here, but meh. */
606 last
= LLVMGetOperand(last
, 0);
608 if (LLVMIsAAllocaInst(last
)) {
609 /* "alloca" is just generically all variables on the
610 * stack, this does not refer to C alloca() calls
612 * looking at the control flow in the function can
613 * give better results here, it's just not implemented
617 "%s: call to a function pointer variable\n",
620 if (details_fptr_vars
) {
621 char *dump
= LLVMPrintValueToString(called
);
622 printf("%s- %s\n", prefix
, dump
);
623 LLVMDisposeMessage(dump
);
626 json_object_object_add(
628 json_object_new_string("stack_fptr"));
629 } else if (LLVMIsACallInst(last
)) {
630 /* calling the a function pointer returned from
633 struct json_object
*js_indirect
;
635 js_indirect
= js_get_or_make(js_call
, "return_of",
636 json_object_new_array
);
638 process_call(js_indirect
, js_special
, last
, function
);
639 } else if (LLVMIsAConstant(last
)) {
640 /* function pointer is a constant (includes loading
641 * from complicated constants like structs or arrays.)
643 bool hdr_written
= false;
644 walk_const_fptrs(js_call
, last
, prefix
, &hdr_written
);
645 if (details_fptr_consts
&& !hdr_written
)
647 "%s: calls function pointer from constant or global data, but no non-NULL function pointers found\n",
650 char *dump
= LLVMPrintValueToString(called
);
651 fprintf(stderr
, "%s: ??? %s\n", prefix
, dump
);
652 LLVMDisposeMessage(dump
);
655 } else if (!strcmp(called_name
, "_install_element")) {
656 called_type
= FN_INSTALL_ELEMENT
;
658 LLVMValueRef param0
= LLVMGetOperand(instr
, 0);
659 if (!LLVMIsAConstantInt(param0
))
662 long long vty_node
= LLVMConstIntGetSExtValue(param0
);
663 json_object_object_add(js_call
, "vty_node",
664 json_object_new_int64(vty_node
));
666 LLVMValueRef param1
= LLVMGetOperand(instr
, 1);
667 if (!LLVMIsAGlobalVariable(param1
))
670 LLVMValueRef intlz
= LLVMGetInitializer(param1
);
671 assert(intlz
&& LLVMIsConstant(intlz
));
673 LLVMValueKind intlzkind
= LLVMGetValueKind(intlz
);
674 assert(intlzkind
== LLVMConstantStructValueKind
);
676 LLVMValueRef funcptr
= LLVMGetOperand(intlz
, 4);
677 assert(LLVMIsAFunction(funcptr
));
679 size_t target_len
= 0;
681 target
= LLVMGetValueName2(funcptr
, &target_len
);
683 json_object_object_add(
685 json_object_new_string("install_element"));
686 json_object_object_add(
688 json_object_new_string_len(target
, target_len
));
692 json_object_object_add(
694 json_object_new_string("install_element"));
696 } else if (is_thread_sched(called_name
, called_len
)) {
697 called_type
= FN_THREAD_ADD
;
699 json_object_object_add(js_call
, "type",
700 json_object_new_string("thread_sched"));
701 json_object_object_add(
703 json_object_new_string_len(called_name
, called_len
));
706 fparam
= LLVMGetOperand(instr
, 2);
709 size_t target_len
= 0;
711 target
= LLVMGetValueName2(fparam
, &target_len
);
713 json_object_object_add(js_call
, "target",
715 json_object_new_string_len(target
, target_len
));
716 if (!LLVMIsAFunction(fparam
))
717 json_object_object_add(js_call
, "target_unresolved",
718 json_object_new_boolean(true));
720 } else if (!strncmp(called_name
, "_hook_typecheck_",
721 strlen("_hook_typecheck_"))) {
722 struct json_object
*js_hook
, *js_this
;
723 const char *hook_name
;
725 hook_name
= called_name
+ strlen("_hook_typecheck_");
727 json_object_object_add(js_call
, "type",
728 json_object_new_string("hook"));
730 LLVMValueRef param0
= LLVMGetOperand(instr
, 0);
731 if (!LLVMIsAFunction(param0
))
734 size_t target_len
= 0;
736 target
= LLVMGetValueName2(param0
, &target_len
);
738 js_hook
= js_get_or_make(js_special
, "hooks",
739 json_object_new_object
);
740 js_hook
= js_get_or_make(js_hook
, hook_name
,
741 json_object_new_array
);
743 js_this
= json_object_new_object();
744 json_object_array_add(js_hook
, js_this
);
746 dbgloc_add(js_this
, instr
);
747 json_object_object_add(
749 json_object_new_string_len(target
, target_len
));
752 /* TODO (FRR specifics):
753 * - workqueues - not sure we can do much there
756 #endif /* FRR_SPECIFIC */
757 } else if (!strcmp(called_name
, "frr_preinit")) {
758 LLVMValueRef daemoninfo
= LLVMGetOperand(instr
, 0);
760 handle_daemoninfo(js_special
, daemoninfo
);
762 json_object_object_add(
764 json_object_new_string_len(called_name
, called_len
));
766 json_object_object_add(
768 json_object_new_string_len(called_name
, called_len
));
772 for (unsigned argno
= 0; argno
< n_args
; argno
++) {
773 LLVMValueRef param
= LLVMGetOperand(instr
, argno
);
775 const char *target_name
;
777 if (LLVMIsAFunction(param
)) {
778 js_fptrs
= js_get_or_make(js_call
, "funcptrs",
779 json_object_new_array
);
781 target_name
= LLVMGetValueName2(param
, &target_len
);
783 json_object_array_add(js_fptrs
,
784 json_object_new_string_len(
785 target_name
, target_len
));
790 static void process_fn(struct json_object
*funcs
,
791 struct json_object
*js_special
,
792 LLVMValueRef function
)
794 struct json_object
*js_func
, *js_calls
;
797 const char *name_c
= LLVMGetValueName2(function
, &name_len
);
800 name
= strndup(name_c
, name_len
);
802 js_func
= json_object_object_get(funcs
, name
);
804 unsigned file_len
= 0;
805 const char *file
= LLVMGetDebugLocFilename(function
, &file_len
);
806 unsigned line
= LLVMGetDebugLocLine(function
);
808 fprintf(stderr
, "%.*s:%d:%s(): duplicate definition!\n",
809 (int)file_len
, file
, line
, name
);
814 js_func
= json_object_new_object();
815 json_object_object_add(funcs
, name
, js_func
);
818 js_calls
= json_object_new_array();
819 json_object_object_add(js_func
, "calls", js_calls
);
821 dbgloc_add(js_func
, function
);
823 for (LLVMBasicBlockRef basicBlock
= LLVMGetFirstBasicBlock(function
);
824 basicBlock
; basicBlock
= LLVMGetNextBasicBlock(basicBlock
)) {
826 for (LLVMValueRef instr
= LLVMGetFirstInstruction(basicBlock
);
827 instr
; instr
= LLVMGetNextInstruction(instr
)) {
829 if (LLVMIsAIntrinsicInst(instr
))
832 if (LLVMIsACallInst(instr
) || LLVMIsAInvokeInst(instr
))
833 process_call(js_calls
, js_special
, instr
,
839 static void help(int retcode
)
842 "FRR LLVM bitcode to callgraph analyzer\n"
844 "usage: frr-llvm-cg [-q|-v] [-o <JSONOUTPUT>] BITCODEINPUT\n"
846 "\t-o FILENAME\twrite JSON output to file instead of stdout\n"
847 "\t-v\t\tbe more verbose\n"
850 "BITCODEINPUT must be a LLVM binary bitcode file (not text\n"
851 "representation.) Use - to read from stdin.\n"
853 "Note it may be necessary to build this binary tool against\n"
854 "the specific LLVM version that created the bitcode file.\n");
858 int main(int argc
, char **argv
)
861 const char *out
= NULL
;
862 const char *inp
= NULL
;
865 while ((opt
= getopt(argc
, argv
, "hvqo:")) != -1) {
873 if (v_or_q
&& v_or_q
!= 'v')
875 details_fptr_vars
= true;
876 details_fptr_consts
= true;
880 if (v_or_q
&& v_or_q
!= 'q')
882 details_fptr_vars
= false;
883 details_fptr_consts
= false;
894 if (optind
!= argc
- 1)
899 LLVMMemoryBufferRef memoryBuffer
;
903 // check if we are to read our input file from stdin
904 if (!strcmp(inp
, "-")) {
906 ret
= LLVMCreateMemoryBufferWithSTDIN(&memoryBuffer
, &message
);
908 ret
= LLVMCreateMemoryBufferWithContentsOfFile(
909 inp
, &memoryBuffer
, &message
);
913 fprintf(stderr
, "failed to open %s: %s\n", inp
, message
);
918 // now create our module using the memorybuffer
919 LLVMModuleRef module
;
920 if (LLVMParseBitcode2(memoryBuffer
, &module
)) {
921 fprintf(stderr
, "%s: invalid bitcode\n", inp
);
922 LLVMDisposeMemoryBuffer(memoryBuffer
);
926 // done with the memory buffer now, so dispose of it
927 LLVMDisposeMemoryBuffer(memoryBuffer
);
929 dbginfo
= dbginfo_load(module
);
931 struct json_object
*js_root
, *js_funcs
, *js_special
;
933 js_root
= json_object_new_object();
934 js_funcs
= json_object_new_object();
935 json_object_object_add(js_root
, "functions", js_funcs
);
936 js_special
= json_object_new_object();
937 json_object_object_add(js_root
, "special", js_special
);
939 // loop through all the functions in the module
940 for (LLVMValueRef function
= LLVMGetFirstFunction(module
); function
;
941 function
= LLVMGetNextFunction(function
)) {
942 if (LLVMIsDeclaration(function
))
945 process_fn(js_funcs
, js_special
, function
);
949 char tmpout
[strlen(out
) + 5];
951 snprintf(tmpout
, sizeof(tmpout
), "%s.tmp", out
);
952 ret
= json_object_to_file_ext(tmpout
, js_root
,
953 JSON_C_TO_STRING_PRETTY
|
954 JSON_C_TO_STRING_PRETTY_TAB
|
955 JSON_C_TO_STRING_NOSLASHESCAPE
);
957 fprintf(stderr
, "could not write JSON to file\n");
960 if (rename(tmpout
, out
)) {
961 fprintf(stderr
, "could not rename JSON output: %s\n",
967 ret
= json_object_to_fd(1, js_root
,
968 JSON_C_TO_STRING_PRETTY
|
969 JSON_C_TO_STRING_PRETTY_TAB
|
970 JSON_C_TO_STRING_NOSLASHESCAPE
);
972 fprintf(stderr
, "could not write JSON to stdout\n");
977 LLVMDisposeModule(module
);