[llvm] [llvm-readobj] Dump callgraph section info for ELF (PR #157499)

Paul Kirth via llvm-commits llvm-commits at lists.llvm.org
Wed Nov 5 09:13:28 PST 2025


================
@@ -0,0 +1,326 @@
+## Tests how --call-graph-info prints the call graph information.
+# RUN: yaml2obj --docnum=1 %s -o %t
+# RUN: llvm-readelf --call-graph-info %t 2>&1 | FileCheck %s --match-full-lines --allow-empty -DFILE=%t
+# RUN: llvm-readelf --elf-output-style=LLVM --call-graph-info %t 2>&1 | FileCheck %s --match-full-lines --check-prefix=LLVM -DFILE=%t
+# RUN: llvm-readelf --elf-output-style=JSON --pretty-print --call-graph-info %t 2>&1 | FileCheck %s --match-full-lines --check-prefix=JSON -DFILE=%t
+
+## Yaml input is obtained by compiling the below source to object with:
+##   clang -fexperimental-call-graph-section test.c -o test.o
+## then to yaml with:
+##   obj2yaml test.o > test.yaml
+## Remove ProgramHeaders if obj2yaml fails.
+
+## YAML output was generated from the following source:
+##
+## void foo() {}
+## 
+## void bar() {}
+## 
+## int baz(char a) { return 0; }
+## 
+## int caller() {
+##   void (*fp_foo)() = foo;
+##   fp_foo();
+## 
+##   void (*fp_bar)() = bar;
+##   fp_bar();
+## 
+##   char a;
+##   int (*fp_baz)(char) = baz;
+##   fp_baz(a);
+##  
+##   foo();
+##   bar();
+##   baz(a);
+## 
+##   return 0;
+## }
+##
+
+## We do not support GNU format console output for --call-graph-info as it is an LLVM only info.
+# CHECK-NOT: .
+
+# LLVM: 		CallGraph [
+# LLVM-NEXT:   Function {
+# LLVM-NEXT:     Name: _Z3foov
+# LLVM-NEXT:     Version: 0
+# LLVM-NEXT:     IsIndirectTarget: Yes
+# LLVM-NEXT:     TypeId: 0xF85C699BB8EF20A2
+# LLVM-NEXT:     NumDirectCallees: 0
+# LLVM-NEXT:     DirectCallees [
+# LLVM-NEXT:     ]
+# LLVM-NEXT:     NumIndirectTargetTypeIDs: 0
+# LLVM-NEXT:     IndirectTypeIDs: []
+# LLVM-NEXT:   }
+# LLVM-NEXT:   Function {
+# LLVM-NEXT:     Name: _Z3barv
+# LLVM-NEXT:     Version: 0
+# LLVM-NEXT:     IsIndirectTarget: Yes
+# LLVM-NEXT:     TypeId: 0xF85C699BB8EF20A2
+# LLVM-NEXT:     NumDirectCallees: 0
+# LLVM-NEXT:     DirectCallees [
+# LLVM-NEXT:     ]
+# LLVM-NEXT:     NumIndirectTargetTypeIDs: 0
+# LLVM-NEXT:     IndirectTypeIDs: []
+# LLVM-NEXT:   }
+# LLVM-NEXT:   Function {
+# LLVM-NEXT:     Name: _Z3bazc
+# LLVM-NEXT:     Version: 0
+# LLVM-NEXT:     IsIndirectTarget: Yes
+# LLVM-NEXT:     TypeId: 0x308E4B8159BC8654
+# LLVM-NEXT:     NumDirectCallees: 0
+# LLVM-NEXT:     DirectCallees [
+# LLVM-NEXT:     ]
+# LLVM-NEXT:     NumIndirectTargetTypeIDs: 0
+# LLVM-NEXT:     IndirectTypeIDs: []
+# LLVM-NEXT:   }
+# LLVM-NEXT:   Function {
+# LLVM-NEXT:     Name: _Z6callerv
+# LLVM-NEXT:     Version: 0
+# LLVM-NEXT:     IsIndirectTarget: Yes
+# LLVM-NEXT:     TypeId: 0xA9494DEF81A01DC
+# LLVM-NEXT:     NumDirectCallees: 3
+# LLVM-NEXT:     DirectCallees [
+# LLVM-NEXT:       {
+# LLVM-NEXT:         Name: _Z3foov
+# LLVM-NEXT:       }
+# LLVM-NEXT:       {
+# LLVM-NEXT:         Name: _Z3barv
+# LLVM-NEXT:       }
+# LLVM-NEXT:       {
+# LLVM-NEXT:         Name: _Z3bazc
+# LLVM-NEXT:       }
+# LLVM-NEXT:     ]
+# LLVM-NEXT:     NumIndirectTargetTypeIDs: 2
+# LLVM-NEXT:     IndirectTypeIDs: [0xF85C699BB8EF20A2, 0x308E4B8159BC8654]
+# LLVM-NEXT:   }
+# LLVM-NEXT: ]
+
+# JSON:     "CallGraph": [
+# JSON-NEXT:      {
+# JSON-NEXT:        "Function": {
+# JSON-NEXT:          "Name": "_Z3foov",
+# JSON-NEXT:          "Version": 0,
+# JSON-NEXT:          "IsIndirectTarget": true,
+# JSON-NEXT:          "TypeId": 17896295136807035042,
+# JSON-NEXT:          "NumDirectCallees": 0,
+# JSON-NEXT:          "DirectCallees": [],
+# JSON-NEXT:          "NumIndirectTargetTypeIDs": 0,
+# JSON-NEXT:          "IndirectTypeIDs": []
+# JSON-NEXT:        }
+# JSON-NEXT:      },
+# JSON-NEXT:      {
+# JSON-NEXT:        "Function": {
+# JSON-NEXT:          "Name": "_Z3barv",
+# JSON-NEXT:          "Version": 0,
+# JSON-NEXT:          "IsIndirectTarget": true,
+# JSON-NEXT:          "TypeId": 17896295136807035042,
+# JSON-NEXT:          "NumDirectCallees": 0,
+# JSON-NEXT:          "DirectCallees": [],
+# JSON-NEXT:          "NumIndirectTargetTypeIDs": 0,
+# JSON-NEXT:          "IndirectTypeIDs": []
+# JSON-NEXT:        }
+# JSON-NEXT:      },
+# JSON-NEXT:      {
+# JSON-NEXT:        "Function": {
+# JSON-NEXT:          "Name": "_Z3bazc",
+# JSON-NEXT:          "Version": 0,
+# JSON-NEXT:          "IsIndirectTarget": true,
+# JSON-NEXT:          "TypeId": 3498816979441845844,
+# JSON-NEXT:          "NumDirectCallees": 0,
+# JSON-NEXT:          "DirectCallees": [],
+# JSON-NEXT:          "NumIndirectTargetTypeIDs": 0,
+# JSON-NEXT:          "IndirectTypeIDs": []
+# JSON-NEXT:        }
+# JSON-NEXT:      },
+# JSON-NEXT:      {
+# JSON-NEXT:        "Function": {
+# JSON-NEXT:          "Name": "_Z6callerv",
+# JSON-NEXT:          "Version": 0,
+# JSON-NEXT:          "IsIndirectTarget": true,
+# JSON-NEXT:          "TypeId": 762397922298560988,
+# JSON-NEXT:          "NumDirectCallees": 3,
+# JSON-NEXT:          "DirectCallees": [
+# JSON-NEXT:            {
+# JSON-NEXT:              "Name": "_Z3foov"
----------------
ilovepi wrote:

Do we need an object for each direct callee if it's just a single field? do we expect to add more data here (in which case the object makes sense)? If we don't, then a flat list of symbol names seems more appropriate. 

https://github.com/llvm/llvm-project/pull/157499


More information about the llvm-commits mailing list