• Namhyung Kim's avatar
    perf annotate-data: Implement instruction tracking · eb8a55e0
    Namhyung Kim authored
    If it failed to find a variable for the location directly, it might be
    due to a missing variable in the source code.  For example, accessing
    pointer variables in a chain can result in the case like below:
    
      struct foo *foo = ...;
    
      int i = foo->bar->baz;
    
    The DWARF debug information is created for each variable so it'd have
    one for 'foo'.  But there's no variable for 'foo->bar' and then it
    cannot know the type of 'bar' and 'baz'.
    
    The above source code can be compiled to the follow x86 instructions:
    
      mov  0x8(%rax), %rcx
      mov  0x4(%rcx), %rdx   <=== PMU sample
      mov  %rdx, -4(%rbp)
    
    Let's say 'foo' is located in the %rax and it has a pointer to struct
    foo.  But perf sample is captured in the second instruction and there
    is no variable or type info for the %rcx.
    
    It'd be great if compiler could generate debug info for %rcx, but we
    should handle it on our side.  So this patch implements the logic to
    iterate instructions and update the type table for each location.
    
    As it already collected a list of scopes including the target
    instruction, we can use it to construct the type table smartly.
    
      +----------------  scope[0] subprogram
      |
      | +--------------  scope[1] lexical_block
      | |
      | | +------------  scope[2] inlined_subroutine
      | | |
      | | | +----------  scope[3] inlined_subroutine
      | | | |
      | | | | +--------  scope[4] lexical_block
      | | | | |
      | | | | |     ***  target instruction
      ...
    
    Image the target instruction has 5 scopes, each scope will have its own
    variables and parameters.  Then it can start with the innermost scope
    (4).  So it'd search the shortest path from the start of scope[4] to
    the target address and build a list of basic blocks.  Then it iterates
    the basic blocks with the variables in the scope and update the table.
    If it finds a type at the target instruction, then returns it.
    
    Otherwise, it moves to the upper scope[3].  Now it'd search the shortest
    path from the start of scope[3] to the start of scope[4].  Then connect
    it to the existing basic block list.  Then it'd iterate the blocks with
    variables for both scopes.  It can repeat this until it finds a type at
    the target instruction or reaches to the top scope[0].
    
    As the basic blocks contain the shortest path, it won't worry about
    branches and can update the table simply.
    
    The final check will be done by find_matching_type() in the next patch.
    Signed-off-by: default avatarNamhyung Kim <namhyung@kernel.org>
    Cc: Adrian Hunter <adrian.hunter@intel.com>
    Cc: Ian Rogers <irogers@google.com>
    Cc: Ingo Molnar <mingo@kernel.org>
    Cc: Jiri Olsa <jolsa@kernel.org>
    Cc: Linus Torvalds <torvalds@linux-foundation.org>
    Cc: Masami Hiramatsu <mhiramat@kernel.org>
    Cc: Peter Zijlstra <peterz@infradead.org>
    Cc: Stephane Eranian <eranian@google.com>
    Link: https://lore.kernel.org/r/20240319055115.4063940-15-namhyung@kernel.orgSigned-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
    eb8a55e0
annotate-data.c 31 KB