Given this source code:
#include <windows.h>
#include <stdio.h>
void* frames[5]{};
void innermost() {
CaptureStackBackTrace(0, 5, frames, nullptr);
}
void inner() {
innermost();
}
void outer() {
inner();
}
void outermost() {
outer();
}
int main() {
outermost();
printf("innermost: 0x%p\tframe[0]: 0x%p\n", &innermost, frames[0]);
printf(" inner: 0x%p\tframe[1]: 0x%p\n", &inner, frames[1]);
printf(" outer: 0x%p\tframe[2]: 0x%p\n", &outer, frames[2]);
printf("outermost: 0x%p\tframe[3]: 0x%p\n", &outermost, frames[3]);
printf(" main: 0x%p\tframe[4]: 0x%p\n", &main, frames[4]);
return 0;
}
Compile and run like so:
clang-cl /nologo /Zi /c /Od test.cpp
link /nologo /debug /incremental:no test.obj
test.exe
EXPECT: that the addresses in the backtrace are within the functions main, outermost, outer, inner, and innermost
ACTUAL: frame[0] is within innermost, but frame[1] is mainCRTStartup and frame[2] and frame[3] are in kernel32 and ntdll respectively.
innermost: 0x00007FF60BF51000 frame[0]: 0x00007FF60BF51024
inner: 0x00007FF60BF5102C frame[1]: 0x00007FF60BF51A8C
outer: 0x00007FF60BF5103C frame[2]: 0x00007FFACF782310
outermost: 0x00007FF60BF5104C frame[3]: 0x00007FFAD0E5577C
main: 0x00007FF60BF5105C frame[4]: 0x0000000000000000
Compare to cl:
cl /nologo /Zi /c /Od test.cpp
link /nologo /debug /incremental:no test.obj
test.exe
innermost: 0x00007FF7DA951588 frame[0]: 0x00007FF7DA9515B0
inner: 0x00007FF7DA9515B8 frame[1]: 0x00007FF7DA9515C4
outer: 0x00007FF7DA9515D0 frame[2]: 0x00007FF7DA9515DC
outermost: 0x00007FF7DA9515E8 frame[3]: 0x00007FF7DA9515F4
main: 0x00007FF7DA951600 frame[4]: 0x00007FF7DA95160C
I believe the issue here is that clang-cl is omitting the frame pointers for small functions, even with -Od.
Compare the assembly for outermost for clang-cl:
?outermost@@YAXXZ:
000000014000104C: str lr,[sp,#-0x10]!
0000000140001050: bl ?outer@@YAXXZ
0000000140001054: ldr lr,[sp],#0x10
0000000140001058: ret
with the assembly when using cl:
?outermost@@YAXXZ:
0000000140001640: stp fp,lr,[sp,#-0x10]!
0000000140001644: mov fp,sp
0000000140001648: bl ?outer@@YAXXZ
000000014000164C: ldp fp,lr,[sp],#0x10
0000000140001650: ret
Given this source code:
Compile and run like so:
EXPECT: that the addresses in the backtrace are within the functions main, outermost, outer, inner, and innermost
ACTUAL: frame[0] is within innermost, but frame[1] is mainCRTStartup and frame[2] and frame[3] are in kernel32 and ntdll respectively.
Compare to cl:
I believe the issue here is that clang-cl is omitting the frame pointers for small functions, even with -Od.
Compare the assembly for
outermostfor clang-cl:with the assembly when using cl: