#include <libunwind.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_FRAMES 64
#define MAX_NAME 256
#define MAX_EDGES 1024
typedef struct {
char caller[MAX_NAME];
char callee[MAX_NAME];
} Edge;
static Edge edges[MAX_EDGES];
static int edge_count = 0;
// Add edge if not duplicate
static void add_edge(const char* caller, const char* callee) {
for (int i = 0; i < edge_count; i++) {
if (strcmp(edges[i].caller, caller) == 0 && strcmp(edges[i].callee, callee) == 0)
return;
}
if (edge_count < MAX_EDGES) {
strncpy(edges[edge_count].caller, caller, MAX_NAME - 1);
strncpy(edges[edge_count].callee, callee, MAX_NAME - 1);
edge_count++;
}
}
// Capture current stack and build call graph edges
void capture_call_graph(void) {
unw_context_t ctx;
unw_cursor_t cur;
unw_getcontext(&ctx);
unw_init_local(&cur, &ctx);
char frames[MAX_FRAMES][MAX_NAME];
int count = 0;
while (unw_step(&cur) > 0 && count < MAX_FRAMES) {
unw_word_t ip;
unw_get_reg(&cur, UNW_REG_IP, &ip);
frames[count][0] = '\0';
if (unw_get_proc_name(&cur, frames[count], MAX_NAME, NULL) != 0)
snprintf(frames[count], MAX_NAME, "0x%lx", (unsigned long)ip);
count++;
}
// Stack: frames[0]=current, frames[1]=caller, ...
// Create caller -> callee edges
for (int i = 1; i < count; i++) {
add_edge(frames[i], frames[i - 1]);
}
}
// Output graph in DOT format
void print_graph(void) {
printf("digraph call_graph {\n");
for (int i = 0; i < edge_count; i++) {
printf(" \"%s\" -> \"%s\";\n", edges[i].caller, edges[i].callee);
}
printf("}\n");
}
// Example call chain
void leaf_func(void) { capture_call_graph(); }
void mid_func(void) { leaf_func(); }
void root_func(void) { mid_func(); }
int main(void) {
root_func();
print_graph();
return 0;
}
// Compile: gcc call_graph.c -o call_graph -lunwind -lunwind-x86_64
// Visualize: ./call_graph | dot -Tpng -o graph.png