If function set() is called from missing() via tail call (JMP instruction), that means that
the frame for function missing() is not preserved on the stack (return PC and FramePointer).
Modern debuggers, like GDB and LLDB (from D50478), can reconstruct missing frames,
and create artificial ones, based on the call site information (from DWARF - example below).
So, debugger can determine which function is called from main() at the particular PC,
and match it to the corresponding DW_TAG_subprogram DIE.
If function missing() is called from main() via indirect call, generated call site information in DWARF,
doesn't point to the DW_TAG_subprogram DIE, since call target is not known at the compile time.
Debugger needs to determine call target at the runtime, by evaluating expression from DW_AT_GNU_call_site_target.
However, in most cases, the expression which determines call target (usually just register, like in the example above),
cannot be evaluated. In the presented example, value of register $rax is not available at that program point.
Additionally, applying some other optimizations and call mechanisms can cause complete absence of
DW_TAG_GNU_call_site for missing() call site in the main() function.
To sum up, without one frame from the backtrace, if it changes the location of the tainted value, which is expected,
llvm-crash-analyzer cannot perform correct Taint Analysis.
To support creation of artificial frames in the presented case, it is needed to have:
Compiler which is able to generate DW_TAG_GNU_call_site DIEs for (all) indirect call sites. This is not supported in some special cases.
Compiler which could provide entry value expression describing call site target, like it is done for entry values of function parameters.
Debugger which could evaluate indirect call target address and use it to match corresponding DW_TAG_subprogram DIE.
Crash Analyzer runs Taint Analysis on each function from the backtrace, so it depends on LLDB's ability to populate backtrace with proper frames.
Please, consider a backtrace like in the example below: (from llvm-crash-analyzer/test/Analysis/missing-frame.test)
If function
set()
is called frommissing()
via tail call (JMP instruction), that means that the frame for functionmissing()
is not preserved on the stack (return PC and FramePointer). Modern debuggers, like GDB and LLDB (from D50478), can reconstruct missing frames, and create artificial ones, based on the call site information (from DWARF - example below). So, debugger can determine which function is called frommain()
at the particular PC, and match it to the correspondingDW_TAG_subprogram
DIE.If function
missing()
is called frommain()
via indirect call, generated call site information in DWARF, doesn't point to theDW_TAG_subprogram
DIE, since call target is not known at the compile time. Debugger needs to determine call target at the runtime, by evaluating expression fromDW_AT_GNU_call_site_target
.However, in most cases, the expression which determines call target (usually just register, like in the example above), cannot be evaluated. In the presented example, value of register
$rax
is not available at that program point. Additionally, applying some other optimizations and call mechanisms can cause complete absence ofDW_TAG_GNU_call_site
formissing()
call site in themain()
function.To sum up, without one frame from the backtrace, if it changes the location of the tainted value, which is expected, llvm-crash-analyzer cannot perform correct Taint Analysis.
To support creation of artificial frames in the presented case, it is needed to have:
DW_TAG_GNU_call_site
DIEs for (all) indirect call sites. This is not supported in some special cases.DW_TAG_subprogram
DIE.