Trying to get variable dependencies with libclang

如何用 libclang 的前端解析所有的.c .cpp 展開ast tree,目前進度只有 callee 和caller 的關係,還有參數 ,function variable 的資訊 假設你有安裝llvm 應該會在

code
find /usr/lib/x86_64-linux-gnu -name libclang*
/usr/lib/x86_64-linux-gnu/libclang-10.so.1
/usr/lib/x86_64-linux-gnu/libclang-11.so.1
/usr/lib/x86_64-linux-gnu/libclang-cpp.so.10
/usr/lib/x86_64-linux-gnu/libclang-cpp.so.11
ln -s libclang.so.1 libclang.so
/usr/lib/x86_64-linux-gnu/libclang-10.so.1
/usr/lib/x86_64-linux-gnu/libclang-11.so.1
/usr/lib/x86_64-linux-gnu/libclang-cpp.so.10
/usr/lib/x86_64-linux-gnu/libclang-cpp.so.11
/usr/lib/x86_64-linux-gnu/libclang.so <=== 請產生這個檔案 ,到這邊libclang 應該就可以用了

透過 clang 前端本來想要找出 variable 之間的依賴關係,嘗試了蠻多種方式,後來發現有cindex.CompilationDatabase.fromDirectory 這邊也有用 compiledb 將 makefile 裡面的database 給libclang看建立有ast依賴關係的tree 不過還是不太行 ,不過可以得到該專案裡面的所有.c .cpp 建立call graph ,加上一些資訊應該可以更好的看出variable引用關係. 照理說應該在compiler處理應該比較正確哈哈 /home/x213212/cpptest/cppcheck/addons/CoreMark-V5/compile_commands.json

code
# Import necessary libraries
import clang.cindex as cindex
import json
import os

# Initialize libclang
function_name = ""
index = cindex.Index.create()

# Specify the path to the compile_commands.json file
compile_commands_file = '/home/x213212/cpptest/cppcheck/addons/CoreMark-V5/compile_commands.json'

# Read the compile_commands.json file
with open(compile_commands_file, 'r') as f:
    compile_commands_data = json.load(f)

# Create a set to store all .c and .cpp files
source_files = set()

# Iterate through each compilation command
for command_data in compile_commands_data:
    # Get the source file path from the compilation command
    source_file = command_data['file']

    # Check if the file extension is .c or .cpp
    if source_file.endswith('.c') or source_file.endswith('.cpp'):
        source_files.add("/home/x213212/cpptest/cppcheck/addons/CoreMark-V5/" + source_file)

# Create a dictionary to store function call relationships
function_calls = {}

# Iterate through the paths of all .c and .cpp files
for source_file in source_files:
    print(f"Analyzing {source_file}...")
    compile_commands = cindex.CompilationDatabase.fromDirectory('/home/x213212/cpptest/cppcheck/addons/CoreMark-V5/')

    # Get the compilation commands
    commands = compile_commands.getCompileCommands(source_file)

    # Create a list to store compilation options
    file_args = []
    for command in commands:
        for argument in command.arguments:
            if str(argument).find("-I") >= 0:
                file_args.append(argument)

    # Parse the source code file
    translationUnit = index.parse(
        source_file,
        args=file_args,
        options=cindex.TranslationUnit.PARSE_DETAILED_PROCESSING_RECORD
    )

    if not translationUnit:
        print(f"Failed to parse translation unit for {source_file}")
    else:
        # Get the root node of the abstract syntax tree (AST)
        rootCursor = translationUnit.cursor

        # Recursive function for traversing every node in the AST
        def visit(cursor, depth=0):
            global function_name
            if cursor.kind == cindex.CursorKind.FUNCTION_DECL:
                # When a function declaration is found
                function_name = cursor.displayname
                if function_name not in function_calls:
                    function_calls[function_name] = set()

            # Print other functions called by this function
            for child in cursor.get_children():
                if child.kind == cindex.CursorKind.CALL_EXPR:
                    callee = child.referenced
                    if callee:
                        callee_name = callee.displayname
                        function_calls[function_name].add(callee_name)

            for child in cursor.get_children():
                visit(child, depth + 1)

        # Call the traversal function
        visit(rootCursor)

function_calls_record = []

# Function to print function calls
def print_function_calls(caller, depth=1):
    if caller in function_calls_record:
        return
    else:
        function_calls_record.append(caller)
    for callee in function_calls[caller]:
        if callee in function_calls_record:
            return
        else:
            function_calls_record.append(callee)

        indent = "  " * depth
        print(f"{indent}Function Declaration: {caller}")
        print(f"{indent}  Callee: {callee}")
        print_function_calls(callee, depth + 1)

total_call_record = []

# Function to print function call stacks
def print_function_calls(caller, depth=0):
    global function_calls_record
    if caller in function_calls_record:
        return
    else:
        function_calls_record.append(caller)
    indent = "  " * depth
    print(f"{indent}Caller: {caller}")
    if caller in function_calls:
        for callee in function_calls[caller]:
            if callee in function_calls_record:
                return
            else:
                function_calls_record.append(callee)

            indent = "  " * (depth+1)

            print(f"{indent}Callee: {callee}")
            if callee in function_calls:
                for x in function_calls[callee]:
                    print_function_calls(x, depth + 2)

# Traverse all functions and record function call stacks
function_calls_record = []
for caller in function_calls:
    function_calls_record = []
    print_function_calls(caller)
    total_call_record.append(function_calls_record)

# possible_callers = []  # Use a list to store possible callers

# Function to find possible callers of a target function
# def find_possible_callers(target_function):
#     global possible_callers
#     for call_record in total_call_record:
#         if target_function in call_record:
#             if target_function not in possible_callers:
#                 possible_callers.append(target_function)
#             for x in call_record[call_record.index(target_function):]:
#                 if x != target_function and x not in possible_callers:
#                     possible_callers.append(x)
#                     find_possible_callers(x)
#     return possible_callers

# # Example: Find possible callers of the "matrix_test" function
# target_function = 'matrix_test(ee_u32, MATRES *, MATDAT *, MATDAT *, MATDAT)'
# possible_callers = find_possible_callers(target_function)

# if possible_callers:
#     print(f"Possible callers of {target_function}:")
#     for caller in possible_callers:
#         print(f"  {caller}")
# else:
#     print(f"No possible callers found for {target_function}")
code
Analyzing /home/x213212/cpptest/cppcheck/addons/CoreMark-V5/platform/utils.c...
Analyzing /home/x213212/cpptest/cppcheck/addons/CoreMark-V5/platform/stubs/isatty.c...
Analyzing /home/x213212/cpptest/cppcheck/addons/CoreMark-V5/platform/stubs/fstat.c...
Analyzing /home/x213212/cpptest/cppcheck/addons/CoreMark-V5/platform/stubs/read.c...
Analyzing /home/x213212/cpptest/cppcheck/addons/CoreMark-V5/platform/stubs/write.c...
Analyzing /home/x213212/cpptest/cppcheck/addons/CoreMark-V5/platform/reset.c...
Analyzing /home/x213212/cpptest/cppcheck/addons/CoreMark-V5/platform/stubs/close.c...
Analyzing /home/x213212/cpptest/cppcheck/addons/CoreMark-V5/platform/stubs/_exit.c...
Analyzing /home/x213212/cpptest/cppcheck/addons/CoreMark-V5/platform/stubs/write_hex.c...
Analyzing /home/x213212/cpptest/cppcheck/addons/CoreMark-V5/platform/uart.c...
Analyzing /home/x213212/cpptest/cppcheck/addons/CoreMark-V5/platform/platform.c...
Analyzing /home/x213212/cpptest/cppcheck/addons/CoreMark-V5/demo/core_list_join.c...
Analyzing /home/x213212/cpptest/cppcheck/addons/CoreMark-V5/platform/stubs/lseek.c...
Analyzing /home/x213212/cpptest/cppcheck/addons/CoreMark-V5/platform/stubs/sbrk.c...
Analyzing /home/x213212/cpptest/cppcheck/addons/CoreMark-V5/demo/core_util.c...
Analyzing /home/x213212/cpptest/cppcheck/addons/CoreMark-V5/demo/core_state.c...
Analyzing /home/x213212/cpptest/cppcheck/addons/CoreMark-V5/demo/core_matrix.c...
Analyzing /home/x213212/cpptest/cppcheck/addons/CoreMark-V5/demo/core_portme.c...
Analyzing /home/x213212/cpptest/cppcheck/addons/CoreMark-V5/demo/core_main.c...
Caller: remove(const char *)
Caller: rename(const char *, const char *)
Caller: renameat(int, const char *, int, const char *)
Caller: tmpfile()
Caller: tmpnam(char *)
Caller: tmpnam_r(char *)
Caller: tempnam(const char *, const char *)
Caller: fclose(FILE *)
Caller: fflush(FILE *)
Caller: fflush_unlocked(FILE *)
Caller: fopen(const char *restrict, const char *restrict)
Caller: freopen(const char *restrict, const char *restrict, FILE *restrict)
Caller: fdopen(int, const char *)
Caller: fmemopen(void *, int, const char *)
Caller: open_memstream(char **, int *)
Caller: setbuf(FILE *restrict, char *restrict)
Caller: setvbuf(FILE *restrict, char *restrict, int, int)
Caller: setbuffer(FILE *restrict, char *restrict, int)
Caller: setlinebuf(FILE *)
Caller: fprintf(FILE *restrict, const char *restrict, ...)
Caller: printf(const char *restrict, ...)
Caller: sprintf(char *restrict, const char *restrict, ...)
Caller: vfprintf(FILE *restrict, const char *restrict, int)
Caller: vprintf(const char *restrict, int)
Caller: vsprintf(char *restrict, const char *restrict, int)
Caller: snprintf(char *restrict, int, const char *restrict, ...)
Caller: vsnprintf(char *restrict, int, const char *restrict, int)
Caller: vdprintf(int, const char *restrict, int)
Caller: dprintf(int, const char *restrict, ...)
Caller: fscanf(FILE *restrict, const char *restrict, ...)
Caller: scanf(const char *restrict, ...)
Caller: sscanf(const char *restrict, const char *restrict, ...)
Caller: vfscanf(FILE *restrict, const char *restrict, int)
Caller: vscanf(const char *restrict, int)
Caller: vsscanf(const char *restrict, const char *restrict, int)
Caller: fgetc(FILE *)
Caller: getc(FILE *)
Caller: getchar()
Caller: getc_unlocked(FILE *)
Caller: getchar_unlocked()
Caller: fgetc_unlocked(FILE *)
Caller: fputc(int, FILE *)
Caller: putc(int, FILE *)
Caller: putchar(int)
Caller: fputc_unlocked(int, FILE *)
Caller: putc_unlocked(int, FILE *)
Caller: putchar_unlocked(int)
Caller: getw(FILE *)
Caller: putw(int, FILE *)
Caller: fgets(char *restrict, int, FILE *restrict)
Caller: __getdelim(char **restrict, int *restrict, int, FILE *restrict)
Caller: getdelim(char **restrict, int *restrict, int, FILE *restrict)
Caller: getline(char **restrict, int *restrict, FILE *restrict)
Caller: fputs(const char *restrict, FILE *restrict)
Caller: puts(const char *)
Caller: ungetc(int, FILE *)
Caller: fread(void *restrict, int, int, FILE *restrict)
Caller: fwrite(const void *restrict, int, int, FILE *restrict)
Caller: fread_unlocked(void *restrict, int, int, FILE *restrict)
Caller: fwrite_unlocked(const void *restrict, int, int, FILE *restrict)
Caller: fseek(FILE *, long, int)
Caller: ftell(FILE *)
Caller: rewind(FILE *)
Caller: fseeko(FILE *, __off_t, int)
Caller: ftello(FILE *)
Caller: fgetpos(FILE *restrict, fpos_t *restrict)
Caller: fsetpos(FILE *, const fpos_t *)
Caller: clearerr(FILE *)
Caller: feof(FILE *)
Caller: ferror(FILE *)
Caller: clearerr_unlocked(FILE *)
Caller: feof_unlocked(FILE *)
Caller: ferror_unlocked(FILE *)
Caller: perror(const char *)
Caller: fileno(FILE *)
Caller: fileno_unlocked(FILE *)
Caller: popen(const char *, const char *)
Caller: pclose(FILE *)
Caller: ctermid(char *)
Caller: flockfile(FILE *)
Caller: ftrylockfile(FILE *)
Caller: funlockfile(FILE *)
Caller: __uflow(FILE *)
Caller: __overflow(FILE *, int)
Caller: get_timer_freq()
Caller: get_timer_value()
Caller: access(const char *, int)
Caller: faccessat(int, const char *, int, int)
Caller: lseek(int, __off_t, int)
Caller: close(int)
Caller: read(int, void *, int)
Caller: write(int, const void *, int)
Caller: pread(int, void *, int, __off_t)
Caller: pwrite(int, const void *, int, __off_t)
Caller: pipe(int *)
Caller: alarm(unsigned int)
Caller: sleep(unsigned int)
Caller: ualarm(__useconds_t, __useconds_t)
Caller: usleep(__useconds_t)
Caller: pause()
Caller: chown(const char *, __uid_t, __gid_t)
Caller: fchown(int, __uid_t, __gid_t)
Caller: lchown(const char *, __uid_t, __gid_t)
Caller: fchownat(int, const char *, __uid_t, __gid_t, int)
Caller: chdir(const char *)
Caller: fchdir(int)
Caller: getcwd(char *, int)
Caller: getwd(char *)
Caller: dup(int)
Caller: dup2(int, int)
Caller: execve(const char *, char *const *, char *const *)
Caller: fexecve(int, char *const *, char *const *)
Caller: execv(const char *, char *const *)
Caller: execle(const char *, const char *, ...)
Caller: execl(const char *, const char *, ...)
Caller: execvp(const char *, char *const *)
Caller: execlp(const char *, const char *, ...)
Caller: nice(int)
Caller: _exit(int)
  Callee: write_hex(int, unsigned long)
Caller: pathconf(const char *, int)
Caller: fpathconf(int, int)
Caller: sysconf(int)
Caller: confstr(int, char *, int)
Caller: getpid()
Caller: getppid()
Caller: getpgrp()
Caller: __getpgid(__pid_t)
Caller: getpgid(__pid_t)
Caller: setpgid(__pid_t, __pid_t)
Caller: setpgrp()
Caller: setsid()
Caller: getsid(__pid_t)
Caller: getuid()
Caller: geteuid()
Caller: getgid()
Caller: getegid()
Caller: getgroups(int, __gid_t *)
Caller: setuid(__uid_t)
Caller: setreuid(__uid_t, __uid_t)
Caller: seteuid(__uid_t)
Caller: setgid(__gid_t)
Caller: setregid(__gid_t, __gid_t)
Caller: setegid(__gid_t)
Caller: fork()
Caller: vfork()
Caller: ttyname(int)
Caller: ttyname_r(int, char *, int)
Caller: isatty(int)
Caller: ttyslot()
Caller: link(const char *, const char *)
Caller: linkat(int, const char *, int, const char *, int)
Caller: symlink(const char *, const char *)
Caller: readlink(const char *restrict, char *restrict, int)
Caller: symlinkat(const char *, int, const char *)
Caller: readlinkat(int, const char *restrict, char *restrict, int)
Caller: unlink(const char *)
Caller: unlinkat(int, const char *, int)
Caller: rmdir(const char *)
Caller: tcgetpgrp(int)
Caller: tcsetpgrp(int, __pid_t)
Caller: getlogin()
Caller: getlogin_r(char *, int)
Caller: setlogin(const char *)
Caller: getopt(int, char *const *, const char *)
Caller: gethostname(char *, int)
Caller: sethostname(const char *, int)
Caller: sethostid(long)
Caller: getdomainname(char *, int)
Caller: setdomainname(const char *, int)
Caller: vhangup()
Caller: revoke(const char *)
Caller: profil(unsigned short *, int, int, unsigned int)
Caller: acct(const char *)
Caller: getusershell()
Caller: endusershell()
Caller: setusershell()
Caller: daemon(int, int)
Caller: chroot(const char *)
Caller: getpass(const char *)
Caller: fsync(int)
Caller: gethostid()
Caller: sync()
Caller: getpagesize()
Caller: getdtablesize()
Caller: truncate(const char *, __off_t)
Caller: ftruncate(int, __off_t)
Caller: brk(void *)
Caller: sbrk(intptr_t)
Caller: syscall(long, ...)
Caller: lockf(int, int, __off_t)
Caller: fdatasync(int)
Caller: crypt(const char *, const char *)
Caller: getentropy(void *, int)
Caller: write_hex(int, unsigned long)
Caller: _stub(int)
Caller: _isatty(int)
Caller: __errno_location()
Caller: stat(const char *restrict, struct stat *restrict)
Caller: fstat(int, struct stat *)
Caller: fstatat(int, const char *restrict, struct stat *restrict, int)
Caller: lstat(const char *restrict, struct stat *restrict)
Caller: chmod(const char *, __mode_t)
Caller: lchmod(const char *, __mode_t)
Caller: fchmod(int, __mode_t)
Caller: fchmodat(int, const char *, __mode_t, int)
Caller: umask(__mode_t)
Caller: mkdir(const char *, __mode_t)
Caller: mkdirat(int, const char *, __mode_t)
Caller: mknod(const char *, __mode_t, __dev_t)
Caller: mknodat(int, const char *, __mode_t, __dev_t)
Caller: mkfifo(const char *, __mode_t)
Caller: mkfifoat(int, const char *, __mode_t)
Caller: utimensat(int, const char *, const struct timespec *, int)
Caller: futimens(int, const struct timespec *)
Caller: __fxstat(int, int, struct stat *)
Caller: __xstat(int, const char *, struct stat *)
Caller: __lxstat(int, const char *, struct stat *)
Caller: __fxstatat(int, int, const char *, struct stat *, int)
Caller: __xmknod(int, const char *, __mode_t, __dev_t *)
Caller: __xmknodat(int, int, const char *, __mode_t, __dev_t *)
Caller: _fstat(int, struct stat *)
  Callee: isatty(int)
  Callee: _stub(int)
Caller: __bswap_16(__uint16_t)
Caller: __bswap_32(__uint32_t)
Caller: __bswap_64(__uint64_t)
Caller: __uint16_identity(__uint16_t)
Caller: __uint32_identity(__uint32_t)
Caller: __uint64_identity(__uint64_t)
Caller: select(int, fd_set *restrict, fd_set *restrict, fd_set *restrict, struct timeval *restrict)
Caller: pselect(int, fd_set *restrict, fd_set *restrict, fd_set *restrict, const struct timespec *restrict, const __sigset_t *restrict)
Caller: _read(int, void *, int)
  Callee: _stub(int)
Caller: memcpy(void *restrict, const void *restrict, int)
Caller: memmove(void *, const void *, int)
Caller: memccpy(void *restrict, const void *restrict, int, int)
Caller: memset(void *, int, int)
Caller: memcmp(const void *, const void *, int)
Caller: memchr(const void *, int, int)
Caller: strcpy(char *restrict, const char *restrict)
Caller: strncpy(char *restrict, const char *restrict, int)
Caller: strcat(char *restrict, const char *restrict)
Caller: strncat(char *restrict, const char *restrict, int)
Caller: strcmp(const char *, const char *)
Caller: strncmp(const char *, const char *, int)
Caller: strcoll(const char *, const char *)
Caller: strxfrm(char *restrict, const char *restrict, int)
Caller: strcoll_l(const char *, const char *, locale_t)
Caller: strxfrm_l(char *, const char *, int, locale_t)
Caller: strdup(const char *)
Caller: strndup(const char *, int)
Caller: strchr(const char *, int)
Caller: strrchr(const char *, int)
Caller: strcspn(const char *, const char *)
Caller: strspn(const char *, const char *)
Caller: strpbrk(const char *, const char *)
Caller: strstr(const char *, const char *)
Caller: strtok(char *restrict, const char *restrict)
Caller: __strtok_r(char *restrict, const char *restrict, char **restrict)
Caller: strtok_r(char *restrict, const char *restrict, char **restrict)
Caller: strlen(const char *)
Caller: strnlen(const char *, int)
Caller: strerror(int)
Caller: strerror_r(int, char *, int)
Caller: strerror_l(int, locale_t)
Caller: bcmp(const void *, const void *, int)
Caller: bcopy(const void *, void *, int)
Caller: bzero(void *, int)
Caller: index(const char *, int)
Caller: rindex(const char *, int)
Caller: ffs(int)
Caller: ffsl(long)
Caller: ffsll(long long)
Caller: strcasecmp(const char *, const char *)
Caller: strncasecmp(const char *, const char *, int)
Caller: strcasecmp_l(const char *, const char *, locale_t)
Caller: strncasecmp_l(const char *, const char *, int, locale_t)
Caller: explicit_bzero(void *, int)
Caller: strsep(char **restrict, const char *restrict)
Caller: strsignal(int)
Caller: __stpcpy(char *restrict, const char *restrict)
Caller: stpcpy(char *restrict, const char *restrict)
Caller: __stpncpy(char *restrict, const char *restrict, int)
Caller: stpncpy(char *restrict, const char *restrict, int)
Caller: _put_char(int)
Caller: _write(int, const void *, int)
  Callee: _stub(int)
Caller: c_startup()
  Callee: __builtin_memcpy(void *, const void *, unsigned long)
  Callee: __builtin_memset(void *, int, unsigned long)
Caller: system_init()
  Callee: uart_init(unsigned int)
Caller: main()
  Callee: portable_fini(core_portable *)
  Callee: core_init_matrix(ee_u32, void *, ee_s32, mat_params *)
  Callee: get_seed_32(int)
  Callee: core_init_state(ee_u32, ee_s16, ee_u8 *)
  Callee: stop_time()
    Caller: get_timer_value()
  Callee: start_time()
    Caller: printf(const char *restrict, ...)
Caller: reset_handler()
  Callee: c_startup()
    Caller: __builtin_memcpy(void *, const void *, unsigned long)
    Caller: __builtin_memset(void *, int, unsigned long)
  Callee: system_init()
    Caller: uart_init(unsigned int)
Caller: _close(int)
  Callee: _stub(int)
Caller: exit(int)
Caller: uart_init(unsigned int)
Caller: uart_putc(int)
Caller: uart_puts(const char *)
  Callee: uart_putc(int)
Caller: outbyte(int)
  Callee: uart_putc(int)
Caller: reset_vector()
Caller: memory_init()
  Callee: __builtin_constant_p()
Caller: portable_init(core_portable *, int *, char **)
Caller: portable_fini(core_portable *)
Caller: iterate(void *)
  Callee: core_bench_list(core_results *, ee_s16)
    Caller: core_list_find(list_head *, list_data *)
    Caller: core_list_remove(list_head *)
    Caller: core_list_reverse(list_head *)
    Caller: crc16(ee_s16, ee_u16)
      Callee: crcu16(ee_u16, ee_u16)
        Caller: crcu8(ee_u8, ee_u16)
    Caller: core_list_mergesort(list_head *, list_cmp, core_results *)
      Callee: cmp
    Caller: core_list_undo_remove(list_head *, list_head *)
Caller: start_time()
  Callee: printf(const char *restrict, ...)
  Callee: get_timer_value()
Caller: stop_time()
  Callee: get_timer_value()
Caller: get_time()
Caller: time_in_secs(uint64_t)
Caller: crcu8(ee_u8, ee_u16)
Caller: crc16(ee_s16, ee_u16)
  Callee: crcu16(ee_u16, ee_u16)
    Caller: crcu8(ee_u8, ee_u16)
Caller: crcu16(ee_u16, ee_u16)
  Callee: crcu8(ee_u8, ee_u16)
Caller: crcu32(ee_u32, ee_u16)
  Callee: crc16(ee_s16, ee_u16)
    Caller: crcu16(ee_u16, ee_u16)
      Callee: crcu8(ee_u8, ee_u16)
Caller: check_data_types()
  Callee: printf(const char *restrict, ...)
Caller: portable_malloc(ee_size_t)
Caller: portable_free(void *)
Caller: parseval(char *)
Caller: core_list_init(ee_u32, list_head *, ee_s16)
  Callee: core_list_insert_new(list_head *, list_data *, list_head **, list_data **, list_head *, list_data *)
    Caller: copy_info(list_data *, list_data *)
Caller: core_bench_list(core_results *, ee_s16)
  Callee: core_list_find(list_head *, list_data *)
  Callee: core_list_remove(list_head *)
  Callee: core_list_reverse(list_head *)
  Callee: crc16(ee_s16, ee_u16)
    Caller: crcu16(ee_u16, ee_u16)
      Callee: crcu8(ee_u8, ee_u16)
  Callee: core_list_mergesort(list_head *, list_cmp, core_results *)
    Caller: cmp
  Callee: core_list_undo_remove(list_head *, list_head *)
Caller: core_init_state(ee_u32, ee_s16, ee_u8 *)
Caller: core_bench_state(ee_u32, ee_u8 *, ee_s16, ee_s16, ee_s16, ee_u16)
  Callee: crcu32(ee_u32, ee_u16)
    Caller: crc16(ee_s16, ee_u16)
      Callee: crcu16(ee_u16, ee_u16)
        Caller: crcu8(ee_u8, ee_u16)
  Callee: core_state_transition(ee_u8 **, ee_u32 *)
    Caller: ee_isdigit(ee_u8)
Caller: core_init_matrix(ee_u32, void *, ee_s32, mat_params *)
Caller: core_bench_matrix(mat_params *, ee_s16, ee_u16)
  Callee: matrix_test(ee_u32, MATRES *, MATDAT *, MATDAT *, MATDAT)
    Caller: matrix_sum(ee_u32, MATRES *, MATDAT)
    Caller: matrix_mul_const(ee_u32, MATRES *, MATDAT *, MATDAT)
    Caller: matrix_mul_matrix_bitextract(ee_u32, MATRES *, MATDAT *, MATDAT *)
    Caller: matrix_mul_matrix(ee_u32, MATRES *, MATDAT *, MATDAT *)
    Caller: crc16(ee_s16, ee_u16)
      Callee: crcu16(ee_u16, ee_u16)
        Caller: crcu8(ee_u8, ee_u16)
    Caller: matrix_add_const(ee_u32, MATDAT *, MATDAT)
    Caller: matrix_mul_vect(ee_u32, MATRES *, MATDAT *, MATDAT *)
Caller: core_list_find(list_head *, list_data *)
Caller: core_list_reverse(list_head *)
Caller: core_list_remove(list_head *)
Caller: core_list_undo_remove(list_head *, list_head *)
Caller: core_list_insert_new(list_head *, list_data *, list_head **, list_data **, list_head *, list_data *)
  Callee: copy_info(list_data *, list_data *)
Caller: core_list_mergesort(list_head *, list_cmp, core_results *)
  Callee: cmp
Caller: calc_func(ee_s16 *, core_results *)
  Callee: core_bench_state(ee_u32, ee_u8 *, ee_s16, ee_s16, ee_s16, ee_u16)
    Caller: crcu32(ee_u32, ee_u16)
      Callee: crc16(ee_s16, ee_u16)
        Caller: crcu16(ee_u16, ee_u16)
          Callee: crcu8(ee_u8, ee_u16)
    Caller: core_state_transition(ee_u8 **, ee_u32 *)
      Callee: ee_isdigit(ee_u8)
Caller: cmp_complex(list_data *, list_data *, core_results *)
  Callee: calc_func(ee_s16 *, core_results *)
    Caller: core_bench_state(ee_u32, ee_u8 *, ee_s16, ee_s16, ee_s16, ee_u16)
      Callee: crcu32(ee_u32, ee_u16)
        Caller: crc16(ee_s16, ee_u16)
          Callee: crcu16(ee_u16, ee_u16)
            Caller: crcu8(ee_u8, ee_u16)
      Callee: core_state_transition(ee_u8 **, ee_u32 *)
        Caller: ee_isdigit(ee_u8)
    Caller: core_bench_matrix(mat_params *, ee_s16, ee_u16)
      Callee: matrix_test(ee_u32, MATRES *, MATDAT *, MATDAT *, MATDAT)
        Caller: matrix_sum(ee_u32, MATRES *, MATDAT)
        Caller: matrix_mul_const(ee_u32, MATRES *, MATDAT *, MATDAT)
        Caller: matrix_mul_matrix_bitextract(ee_u32, MATRES *, MATDAT *, MATDAT *)
        Caller: matrix_mul_matrix(ee_u32, MATRES *, MATDAT *, MATDAT *)
        Caller: matrix_add_const(ee_u32, MATDAT *, MATDAT)
        Caller: matrix_mul_vect(ee_u32, MATRES *, MATDAT *, MATDAT *)
Caller: cmp_idx(list_data *, list_data *, core_results *)
Caller: copy_info(list_data *, list_data *)
Caller: _lseek(int, off_t, int)
  Callee: isatty(int)
  Callee: _stub(int)
Caller: _sbrk(int)
Caller: get_seed_32(int)
Caller: core_state_transition(ee_u8 **, ee_u32 *)
  Callee: ee_isdigit(ee_u8)
Caller: ee_isdigit(ee_u8)
Caller: matrix_test(ee_u32, MATRES *, MATDAT *, MATDAT *, MATDAT)
  Callee: matrix_sum(ee_u32, MATRES *, MATDAT)
  Callee: matrix_mul_const(ee_u32, MATRES *, MATDAT *, MATDAT)
  Callee: matrix_mul_matrix_bitextract(ee_u32, MATRES *, MATDAT *, MATDAT *)
  Callee: matrix_mul_matrix(ee_u32, MATRES *, MATDAT *, MATDAT *)
  Callee: crc16(ee_s16, ee_u16)
    Caller: crcu16(ee_u16, ee_u16)
      Callee: crcu8(ee_u8, ee_u16)
  Callee: matrix_add_const(ee_u32, MATDAT *, MATDAT)
  Callee: matrix_mul_vect(ee_u32, MATRES *, MATDAT *, MATDAT *)
Caller: matrix_sum(ee_u32, MATRES *, MATDAT)
Caller: matrix_mul_const(ee_u32, MATRES *, MATDAT *, MATDAT)
Caller: matrix_mul_vect(ee_u32, MATRES *, MATDAT *, MATDAT *)
Caller: matrix_mul_matrix(ee_u32, MATRES *, MATDAT *, MATDAT *)
Caller: matrix_mul_matrix_bitextract(ee_u32, MATRES *, MATDAT *, MATDAT *)
Caller: matrix_add_const(ee_u32, MATDAT *, MATDAT)
Caller: __ctype_get_mb_cur_max()
Caller: atof(const char *)
Caller: atoi(const char *)
Caller: atol(const char *)
Caller: atoll(const char *)
Caller: strtod(const char *restrict, char **restrict)
Caller: strtof(const char *restrict, char **restrict)
Caller: strtold(const char *restrict, char **restrict)
Caller: strtol(const char *restrict, char **restrict, int)
Caller: strtoul(const char *restrict, char **restrict, int)
Caller: strtoq(const char *restrict, char **restrict, int)
Caller: strtouq(const char *restrict, char **restrict, int)
Caller: strtoll(const char *restrict, char **restrict, int)
Caller: strtoull(const char *restrict, char **restrict, int)
Caller: l64a(long)
Caller: a64l(const char *)
Caller: random()
Caller: srandom(unsigned int)
Caller: initstate(unsigned int, char *, int)
Caller: setstate(char *)
Caller: random_r(struct random_data *restrict, int32_t *restrict)
Caller: srandom_r(unsigned int, struct random_data *)
Caller: initstate_r(unsigned int, char *restrict, int, struct random_data *restrict)
Caller: setstate_r(char *restrict, struct random_data *restrict)
Caller: rand()
Caller: srand(unsigned int)
Caller: rand_r(unsigned int *)
Caller: drand48()
Caller: erand48(unsigned short *)
Caller: lrand48()
Caller: nrand48(unsigned short *)
Caller: mrand48()
Caller: jrand48(unsigned short *)
Caller: srand48(long)
Caller: seed48(unsigned short *)
Caller: lcong48(unsigned short *)
Caller: drand48_r(struct drand48_data *restrict, double *restrict)
Caller: erand48_r(unsigned short *, struct drand48_data *restrict, double *restrict)
Caller: lrand48_r(struct drand48_data *restrict, long *restrict)
Caller: nrand48_r(unsigned short *, struct drand48_data *restrict, long *restrict)
Caller: mrand48_r(struct drand48_data *restrict, long *restrict)
Caller: jrand48_r(unsigned short *, struct drand48_data *restrict, long *restrict)
Caller: srand48_r(long, struct drand48_data *)
Caller: seed48_r(unsigned short *, struct drand48_data *)
Caller: lcong48_r(unsigned short *, struct drand48_data *)
Caller: malloc(int)
Caller: calloc(int, int)
Caller: realloc(void *, int)
Caller: reallocarray(void *, int, int)
Caller: free(void *)
Caller: alloca(int)
Caller: valloc(int)
Caller: posix_memalign(void **, int, int)
Caller: aligned_alloc(int, int)
Caller: abort()
Caller: atexit(void (*)(void))
Caller: at_quick_exit(void (*)(void))
Caller: on_exit(void (*)(int, void *), void *)
Caller: quick_exit(int)
Caller: _Exit(int)
Caller: getenv(const char *)
Caller: putenv(char *)
Caller: setenv(const char *, const char *, int)
Caller: unsetenv(const char *)
Caller: clearenv()
Caller: mktemp(char *)
Caller: mkstemp(char *)
Caller: mkstemps(char *, int)
Caller: mkdtemp(char *)
Caller: system(const char *)
Caller: realpath(const char *restrict, char *restrict)
Caller: bsearch(const void *, const void *, int, int, __compar_fn_t)
Caller: qsort(void *, int, int, __compar_fn_t)
Caller: abs(int)
Caller: labs(long)
Caller: llabs(long long)
Caller: div(int, int)
Caller: ldiv(long, long)
Caller: lldiv(long long, long long)
Caller: ecvt(double, int, int *restrict, int *restrict)
Caller: fcvt(double, int, int *restrict, int *restrict)
Caller: gcvt(double, int, char *)
Caller: qecvt(long double, int, int *restrict, int *restrict)
Caller: qfcvt(long double, int, int *restrict, int *restrict)
Caller: qgcvt(long double, int, char *)
Caller: ecvt_r(double, int, int *restrict, int *restrict, char *restrict, int)
Caller: fcvt_r(double, int, int *restrict, int *restrict, char *restrict, int)
Caller: qecvt_r(long double, int, int *restrict, int *restrict, char *restrict, int)
Caller: qfcvt_r(long double, int, int *restrict, int *restrict, char *restrict, int)
Caller: mblen(const char *, int)
Caller: mbtowc(int *restrict, const char *restrict, int)
Caller: wctomb(char *, int)
Caller: mbstowcs(int *restrict, const char *restrict, int)
Caller: wcstombs(char *restrict, const int *restrict, int)
Caller: rpmatch(const char *)
Caller: getsubopt(char **restrict, char *const *restrict, char **restrict)
Caller: getloadavg(double *, int)

再加料一下印出 variable 和 function param

code
import clang.cindex as cindex
import json
import os

function_name = ""

# Initialize libclang
index = cindex.Index.create()

# Specify the path to the compile_commands.json file
compile_commands_file = '/home/x213212/cpptest/cppcheck/addons/CoreMark-V5/compile_commands.json'

# Read the compile_commands.json file
with open(compile_commands_file, 'r') as f:
    compile_commands_data = json.load(f)

# Create a collection to store all .c and .cpp files
source_files = set()

# Iterate through each compilation command
for command_data in compile_commands_data:
    # Get the source file path from the compilation command
    source_file = command_data['file']

    # Check if the file extension is .c or .cpp
    if source_file.endswith('.c') or source_file.endswith('.cpp'):
        source_files.add("/home/x213212/cpptest/cppcheck/addons/CoreMark-V5/" + source_file)

# Create a dictionary to store function call relationships
function_calls = {}
function_variable = {}
function_param = {}

# Iterate through the paths of all .c and .cpp files
for source_file in source_files:
    print(f"Analyzing {source_file}...")

    # Create a CompilationDatabase for the specified directory
    compile_commands = cindex.CompilationDatabase.fromDirectory('/home/x213212/cpptest/cppcheck/addons/CoreMark-V5/')

    # Get the compilation commands
    commands = compile_commands.getCompileCommands(source_file)

    # Create a list to store compilation options
    file_args = []
    for command in commands:
        for argument in command.arguments:
            if str(argument).find("-I") >= 0:
                file_args.append(argument)

    # Parse the source code file
    translationUnit = index.parse(
        source_file,
        args=file_args,
        options=cindex.TranslationUnit.PARSE_DETAILED_PROCESSING_RECORD
    )

    if not translationUnit:
        print(f"Failed to parse translation unit for {source_file}")
    else:
        # Get the root node of the abstract syntax tree
        rootCursor = translationUnit.cursor

        # Recursive function to traverse each node in the abstract syntax tree
        def visit(cursor, depth=0):
            global function_name
            if cursor.kind == cindex.CursorKind.FUNCTION_DECL:
                # When a function declaration is found
                function_name = cursor.displayname
                if function_name not in function_calls:
                    function_calls[function_name] = set()
                if function_name not in function_variable:
                    function_variable[function_name] = set()
                if function_name not in function_param:
                    function_param[function_name] = set()

                # Get function parameter information
                for param in cursor.get_children():
                    if param.kind == cindex.CursorKind.PARM_DECL:
                        param_name = param.displayname
                        param_type = param.type.spelling
                        param_info = f" Parameter Name: {param_name} | Parameter Type: {param_type}"
                        function_param[function_name].add(param_info)

            # Print other functions called by this function
            for child in cursor.get_children():
                if child.kind == cindex.CursorKind.CALL_EXPR:
                    callee = child.referenced
                    if callee:
                        callee_name = callee.displayname
                        function_calls[function_name].add(callee_name)
                if child.kind:
                    # Get variable declarations referenced by DECL_REF_EXPR
                    var_decl = child.get_definition()
                    if var_decl and var_decl.kind == cindex.CursorKind.VAR_DECL:
                        output = " Variable Name:"+ str(child.displayname) + "|Variable Location:"+ str(var_decl.location.file.name)+ ":"+  str(var_decl.location.line)+ ":"+ str(var_decl.location.column)
                        function_variable[function_name].add(output)

            for child in cursor.get_children():
                visit(child, depth + 1)

        # Call the traversal function
        visit(rootCursor)

# Record of function calls
function_calls_record = []

def print_function_calls(caller, depth=1):
    if caller in function_calls_record:
        return
    else:
        function_calls_record.append(caller)
    for callee in function_calls[caller]:
        if callee in function_calls_record:
            return
        else:
            function_calls_record.append(callee)

        indent = "  " * depth
        print(f"{indent}Function Declaration: {caller}")
        print(f"{indent}  Callee: {callee}")
        print_function_calls(callee, depth + 1)

total_call_record = []
def print_function_param(function_name, depth):
    if function_name in function_param:
        get_function_param= function_param[function_name]
        indent = "  " * depth
        for x in get_function_param:
            print(f"{indent} {x}")

def print_function_variable(function_name, depth):
    if function_name in function_variable:
        get_function_variable = function_variable[function_name]
        indent = "  " * depth
        for x in get_function_variable:
            print(f"{indent} {x}")

def print_function_calls(caller, depth=0):
    global function_calls_record
    if caller in function_calls_record:
        return
    else:
        function_calls_record.append(caller)
    indent = "  " * depth
    print(f"{indent} Caller: {caller}")
    print_function_param(caller, depth)
    print_function_variable(caller, depth)
    if caller in function_calls:
        for callee in function_calls[caller]:
            if callee in function_calls_record:
                return
            else:
                function_calls_record.append(callee)

            indent = "  " * (depth + 1)
            print(f"{indent} Callee: {callee}")
            print_function_param(callee, depth+ 1)
            print_function_variable(caller, depth+ 1)
            if callee in function_calls:
                for x in function_calls[callee]:
                    print_function_calls(x, depth + 2)

# Iterate through all functions and record function call stacks
function_calls_record = []
for caller in function_calls:
    function_calls_record = []
    print_function_calls(caller)
    print("------------------------------------------------")
    total_call_record.append(function_calls_record)

output

code
------------------------------------------------
 Caller: calc_func(ee_s16 *, core_results *)
  Parameter Name: pdata | Parameter Type: ee_s16 *
  Parameter Name: res | Parameter Type: core_results *
  Variable Name:data|Variable Location:/home/x213212/cpptest/cppcheck/addons/CoreMark-V5/demo/core_list_join.c:72:12
  Variable Name:flag|Variable Location:/home/x213212/cpptest/cppcheck/addons/CoreMark-V5/demo/core_list_join.c:81:16
  Variable Name:retval|Variable Location:/home/x213212/cpptest/cppcheck/addons/CoreMark-V5/demo/core_list_join.c:73:12
  Variable Name:dtype|Variable Location:/home/x213212/cpptest/cppcheck/addons/CoreMark-V5/demo/core_list_join.c:82:16
  Variable Name:optype|Variable Location:/home/x213212/cpptest/cppcheck/addons/CoreMark-V5/demo/core_list_join.c:74:12
   Callee: core_bench_matrix(mat_params *, ee_s16, ee_u16)
    Parameter Name: crc | Parameter Type: ee_u16
    Parameter Name: seed | Parameter Type: ee_s16
    Parameter Name: p | Parameter Type: mat_params *
    Variable Name:data|Variable Location:/home/x213212/cpptest/cppcheck/addons/CoreMark-V5/demo/core_list_join.c:72:12
    Variable Name:flag|Variable Location:/home/x213212/cpptest/cppcheck/addons/CoreMark-V5/demo/core_list_join.c:81:16
    Variable Name:retval|Variable Location:/home/x213212/cpptest/cppcheck/addons/CoreMark-V5/demo/core_list_join.c:73:12
    Variable Name:dtype|Variable Location:/home/x213212/cpptest/cppcheck/addons/CoreMark-V5/demo/core_list_join.c:82:16
    Variable Name:optype|Variable Location:/home/x213212/cpptest/cppcheck/addons/CoreMark-V5/demo/core_list_join.c:74:12
     Caller: crc16(ee_s16, ee_u16)
      Parameter Name: crc | Parameter Type: ee_u16
      Parameter Name: newval | Parameter Type: ee_s16
       Callee: crcu16(ee_u16, ee_u16)
        Parameter Name: crc | Parameter Type: ee_u16
        Parameter Name: newval | Parameter Type: ee_u16
         Caller: crcu8(ee_u8, ee_u16)
          Parameter Name: crc | Parameter Type: ee_u16
          Parameter Name: data | Parameter Type: ee_u8
          Variable Name:i|Variable Location:/home/x213212/cpptest/cppcheck/addons/CoreMark-V5/demo/core_util.c:167:11
          Variable Name:carry|Variable Location:/home/x213212/cpptest/cppcheck/addons/CoreMark-V5/demo/core_util.c:167:27
          Variable Name:x16|Variable Location:/home/x213212/cpptest/cppcheck/addons/CoreMark-V5/demo/core_util.c:167:18
     Caller: matrix_test(ee_u32, MATRES *, MATDAT *, MATDAT *, MATDAT)
      Parameter Name: val | Parameter Type: MATDAT
      Parameter Name: B | Parameter Type: MATDAT *
      Parameter Name: N | Parameter Type: ee_u32
      Parameter Name: A | Parameter Type: MATDAT *
      Parameter Name: C | Parameter Type: MATRES *
      Variable Name:crc|Variable Location:/home/x213212/cpptest/cppcheck/addons/CoreMark-V5/demo/core_matrix.c:132:12
      Variable Name:clipval|Variable Location:/home/x213212/cpptest/cppcheck/addons/CoreMark-V5/demo/core_matrix.c:133:12
       Callee: matrix_mul_matrix_bitextract(ee_u32, MATRES *, MATDAT *, MATDAT *)
        Parameter Name: B | Parameter Type: MATDAT *
        Parameter Name: N | Parameter Type: ee_u32
        Parameter Name: A | Parameter Type: MATDAT *
        Parameter Name: C | Parameter Type: MATRES *
        Variable Name:crc|Variable Location:/home/x213212/cpptest/cppcheck/addons/CoreMark-V5/demo/core_matrix.c:132:12
        Variable Name:clipval|Variable Location:/home/x213212/cpptest/cppcheck/addons/CoreMark-V5/demo/core_matrix.c:133:12
       Callee: matrix_mul_vect(ee_u32, MATRES *, MATDAT *, MATDAT *)
        Parameter Name: B | Parameter Type: MATDAT *
        Parameter Name: N | Parameter Type: ee_u32
        Parameter Name: A | Parameter Type: MATDAT *
        Parameter Name: C | Parameter Type: MATRES *
        Variable Name:crc|Variable Location:/home/x213212/cpptest/cppcheck/addons/CoreMark-V5/demo/core_matrix.c:132:12
        Variable Name:clipval|Variable Location:/home/x213212/cpptest/cppcheck/addons/CoreMark-V5/demo/core_matrix.c:133:12
       Callee: matrix_mul_const(ee_u32, MATRES *, MATDAT *, MATDAT)
        Parameter Name: val | Parameter Type: MATDAT
        Parameter Name: N | Parameter Type: ee_u32
        Parameter Name: A | Parameter Type: MATDAT *
        Parameter Name: C | Parameter Type: MATRES *
        Variable Name:crc|Variable Location:/home/x213212/cpptest/cppcheck/addons/CoreMark-V5/demo/core_matrix.c:132:12
        Variable Name:clipval|Variable Location:/home/x213212/cpptest/cppcheck/addons/CoreMark-V5/demo/core_matrix.c:133:12
------------------------------------------------