Skip to content

Conversation

Prabhuk
Copy link
Contributor

@Prabhuk Prabhuk commented Sep 8, 2025

Introduce a new flag --call-graph-info which outputs callgraph ELF
section information to the console as a text output or as JSON output.

Copy link

github-actions bot commented Sep 8, 2025

✅ With the latest revision this PR passed the C/C++ code formatter.

@Prabhuk Prabhuk force-pushed the readelf_callgraph_info branch from 3499c2d to 0b9c46d Compare September 18, 2025 03:09
@Prabhuk Prabhuk requested review from frobtech and ilovepi September 19, 2025 00:12
@ilovepi
Copy link
Contributor

ilovepi commented Sep 22, 2025

Tests failing seems unrelated. Probably rebase.

Comment on lines +10 to +40
# CHECK: {{.*}}llvm-readelf{{.*}}: warning: '[[FILE]]': .callgraph section has unknown type id for 1 indirect targets.
# CHECK-NEXT: Per-function call graph information::
# CHECK-EMPTY:
# CHECK-NEXT: Function:: foo
# CHECK-NEXT: Function PC:: 0x0
# CHECK-NEXT: FormatVersionNumber:: 0
# CHECK-NEXT: Function Kind:: NOT_INDIRECT
# CHECK-NEXT: Indirect callee count:: 0
# CHECK-NEXT: Direct callee count:: 1
# CHECK-NEXT: {
# CHECK-NEXT: CalleePC:: 0x5
# CHECK-NEXT: }
# CHECK-EMPTY:
# CHECK-NEXT: Function:: bar
# CHECK-NEXT: Function PC:: 0x6
# CHECK-NEXT: FormatVersionNumber:: 0
# CHECK-NEXT: Function Kind:: UNKNOWN_TID
# CHECK-NEXT: Indirect callee count:: 1
# CHECK-NEXT: {
# CHECK-NEXT: callsite: 0x9
# CHECK-NEXT: calleeTypeId: 0x10
# CHECK-NEXT: }
# CHECK-NEXT: Direct callee count:: 0
# CHECK-EMPTY:
# CHECK-NEXT: Function:: baz
# CHECK-NEXT: Function PC:: 0xa
# CHECK-NEXT: FormatVersionNumber:: 0
# CHECK-NEXT: Function Kind:: KNOWN_TID
# CHECK-NEXT: Function Type ID:: 0x20
# CHECK-NEXT: Indirect callee count:: 0
# CHECK-NEXT: Direct callee count:: 0
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't this section fail when you do json(and I guess llvm too) output? CHECK lines are always checked no matter the prefix.

Comment on lines +9 to +10

# CHECK: {{.*}}llvm-readelf{{.*}}: warning: '[[FILE]]': .callgraph section has unknown type id for 1 indirect targets.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# CHECK: {{.*}}llvm-readelf{{.*}}: warning: '[[FILE]]': .callgraph section has unknown type id for 1 indirect targets.
# CHECK: warning: '[[FILE]]': .callgraph section has unknown type id for 1 indirect targets.

I don't think you need to check the tool's name do you? What's the convention in other tests?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wanted to use --match-full-lines in my test. Let me try if the test passes if the toolname prefix is not part of the CHECK lines.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a particular reason you want to match full lines? convention? specific criteria?

# JSON-NEXT: "Function": {
# JSON-NEXT: "Name": "foo",
# JSON-NEXT: "Address": 6032,
# JSON-NEXT: "Version": 0,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the version number?

Comment on lines +200 to +201
# JSON-NEXT: "NumIndirectCallSites": 0,
# JSON-NEXT: "NumDirectCallSites": 0
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The arrays of the callsites should always be in the output. the schema needs to be fixed to be easily processable.

Comment on lines +86 to +91
# CHECK-NEXT: Callee:: foo
# CHECK-NEXT: CalleePC:: 0x1790
# CHECK-NEXT: Callee:: bar
# CHECK-NEXT: CalleePC:: 0x17a0
# CHECK-NEXT: Callee:: baz
# CHECK-NEXT: CalleePC:: 0x17b0
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the :: is odd.

Maybe this gets printed as Callee: 0x1790 foo or something like that, since the symbol, pc pair IMO make sense to be on the same line? I don't recall the gnu output conventions, but for LLVM, its kind of haphazard, and some things are very json like, and others are just whatever people felt like.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ack. One of the offline feedback I received is to turn GNU output into a tabular format to match existing readelf output style. I will work on that and update the patch.

Comment on lines +5348 to +5350
(StringRef("While reading call graph info's [") + Component +
StringRef("] for function at [0x") + StringRef(FuncPC.str()) + "]")
.str();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
(StringRef("While reading call graph info's [") + Component +
StringRef("] for function at [0x") + StringRef(FuncPC.str()) + "]")
.str();
(Twine("While reading call graph info's [") + Component +
"] for function at [0x" + FuncPC + "]").str();

But I'd think you'd typically just construct this below in the call to reportError()

Comment on lines +5371 to +5374
Error FormatErr = createError("Unknown format version value [" +
std::to_string(FormatVersionNumber) +
"] in .callgraph section.");
reportError(std::move(FormatErr), "Unknown value");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Error FormatErr = createError("Unknown format version value [" +
std::to_string(FormatVersionNumber) +
"] in .callgraph section.");
reportError(std::move(FormatErr), "Unknown value");
reportError(createError("Unknown format version value [" +
std::to_string(FormatVersionNumber) +
"] in .callgraph section."), "Unknown value");

What you have is fine. I just think this is a bit more typical of what I see in the codebase. either way is OK, so I'd just follow whatever convention this file/library uses.

return CallGraphSection;
}

template <class ELFT> bool ELFDumper<ELFT>::processCallGraphSection() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Am I missing the JSON impl? I know some of that is automagically derived, but usually there's somehting we want expressed differently in the JSON than in the LLVM output.

}
}
W.printNumber("NumDirectCallSites", CGInfo.DirectCallees.size());
if (CGInfo.DirectCallees.size() > 0) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These should always be printed, so a parser can always expect them to be there.

Comment on lines +5512 to +5515
OS << "\nFunction:: " << FuncSymNames;
OS << "\nFunction PC:: " << format("0x%lx", FuncEntryPc);
OS << "\nFormatVersionNumber:: " << CGInfo.FormatVersionNumber;
OS << "\nFunction Kind:: " << GetFuntionKindString(CGInfo.Kind);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not use something like a list scope and the print() APIs, like the later changes?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants