1. 16 Apr, 2024 3 commits
    • Namhyung Kim's avatar
      perf dwarf-aux: Check variable address range properly · 0519fadb
      Namhyung Kim authored
      In match_var_offset(), it just checked the end address of the variable
      with the given offset because it assumed the register holds a pointer
      to the data type and the offset starts from the base.
      
      But I found some cases that the stack pointer (rsp = reg7) register is
      used to pointer a stack variable while the frame base is maintained by a
      different register (rbp = reg6).  In that case, it cannot simply use the
      stack pointer as it cannot guarantee that it points to the frame base.
      So it needs to check both boundaries of the variable location.
      
      Before:
        -----------------------------------------------------------
        find data type for 0x7c(reg7) at tcp_getsockopt+0xb62
        CU for net/ipv4/tcp.c (die:0x7b5f516)
        frame base: cfa=0 fbreg=6
        no pointer or no type
        check variable "tss" failed (die: 0x7b95801)
         variable location: base reg7, offset=0x110
         type='struct scm_timestamping_internal' size=0x30 (die:0x7b8c126)
      
      So the current code just checks register number for the non-PC and
      non-FB registers and assuming it has offset 0.  But this variable has
      offset 0x110 so it should not match to this.
      
      After:
        -----------------------------------------------------------
        find data type for 0x7c(reg7) at tcp_getsockopt+0xb62
        CU for net/ipv4/tcp.c (die:0x7b5f516)
        frame base: cfa=0 fbreg=6
        no pointer or no type
        check variable "zc" failed (die: 0x7b9580a)
         variable location: base=reg7, offset=0x40
         type='struct tcp_zerocopy_receive' size=0x40 (die:7b947f4)
      
      Now it find the correct variable "zc".  It was located at reg7 + 0x40
      and the size if 0x40 which means it should cover [0x40, 0x80).  And the
      access was for reg7 + 0x7c so it found the right one.  But it still
      failed to use the variable and it would be handled 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: Kan Liang <kan.liang@linux.intel.com>
      Cc: Masami Hiramatsu <mhiramat@kernel.org>
      Cc: Peter Zijlstra <peterz@infradead.org>
      Link: https://lore.kernel.org/r/20240412183310.2518474-4-namhyung@kernel.orgSigned-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
      0519fadb
    • Namhyung Kim's avatar
      perf dwarf-aux: Check pointer offset when checking variables · 645af3fb
      Namhyung Kim authored
      In match_var_offset(), it checks the offset range with the target type
      only for non-pointer types.  But it also needs to check the pointer
      types with the target type.
      
      This is because there can be more than one pointer variable located in
      the same register.  Let's look at the following example.  It's looking
      up a variable for reg3 at tcp_get_info+0x62.  It found "sk" variable but
      it wasn't the right one since it accesses beyond the target type (struct
      'sock' in this case) size.
      
        -----------------------------------------------------------
        find data type for 0x7bc(reg3) at tcp_get_info+0x62
        CU for net/ipv4/tcp.c (die:0x7b5f516)
        frame base: cfa=0 fbreg=6
        offset: 1980 is bigger than size: 760
        check variable "sk" failed (die: 0x7b92b2c)
         variable location: reg3
         type='struct sock' size=0x2f8 (die:0x7b63c3ab)
      
      Actually there was another variable "tp" in the function and it's
      located at the same (reg3) because it's just type-casted like below.
      
        void tcp_get_info(struct sock *sk, struct tcp_info *info)
        {
            const struct tcp_sock *tp = tcp_sk(sk);
            ...
      
      The 'struct tcp_sock' contains the 'struct sock' at offset 0 so it can
      just use the same address as a pointer to tcp_sock.  That means it
      should match variables correctly by checking the offset and size.
      Actually it cannot distinguish if the offset was smaller than the size
      of the original struct sock.  But I think it's fine as they are the same
      at that part.
      
      So let's check the target type size and retry if it doesn't match.
      Now it succeeded to find the correct variable.
      
        -----------------------------------------------------------
        find data type for 0x7bc(reg3) at tcp_get_info+0x62
        CU for net/ipv4/tcp.c (die:0x7b5f516)
        frame base: cfa=0 fbreg=6
        found "tp" in scope=1/1 (die: 0x7b92b16) type_offset=0x7bc
         variable location: reg3
         type='struct tcp_sock' size=0xa68 (die:0x7b81380)
      
      Fixes: bc10db8e ("perf annotate-data: Support stack variables")
      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: Kan Liang <kan.liang@linux.intel.com>
      Cc: Masami Hiramatsu <mhiramat@kernel.org>
      Cc: Namhyung Kim <namhyung@kernel.org>
      Cc: Peter Zijlstra <peterz@infradead.org>
      Link: https://lore.kernel.org/r/20240412183310.2518474-3-namhyung@kernel.orgSigned-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
      645af3fb
    • Namhyung Kim's avatar
      perf annotate-data: Improve debug message with location info · 2bc3cf57
      Namhyung Kim authored
      To verify it found the correct variable, let's add the location
      expression to the debug message.
      
        $ perf --debug type-profile annotate --data-type
        ...
        -----------------------------------------------------------
        find data type for 0xaf0(reg15) at schedule+0xeb
        CU for kernel/sched/core.c (die:0x1180523)
        frame base: cfa=0 fbreg=6
        found "rq" in scope=3/4 (die: 0x11b6a00) type_offset=0xaf0
         variable location: reg15
         type='struct rq' size=0xfc0 (die:0x11892e2)
        -----------------------------------------------------------
        find data type for 0x7bc(reg3) at tcp_get_info+0x62
        CU for net/ipv4/tcp.c (die:0x7b5f516)
        frame base: cfa=0 fbreg=6
        offset: 1980 is bigger than size: 760
        check variable "sk" failed (die: 0x7b92b2c)
         variable location: reg3
         type='struct sock' size=0x2f8 (die:0x7b63c3ab)
        -----------------------------------------------------------
        ...
      
      The first case is fine.  It looked up a data type in r15 with offset of
      0xaf0 at schedule+0xeb.  It found the CU die and the frame base info and
      the variable "rq" was found in the scope 3/4.  Its location is the r15
      register and the type size is 0xfc0 which includes 0xaf0.
      
      But the second case is not good.  It looked up a data type in rbx (reg3)
      with offset 0x7bc.  It found a CU and the frame base which is good so
      far.  And it also found a variable "sk" but the access offset is bigger
      than the type size (1980 vs. 760 or 0x7bc vs. 0x2f8).  The variable has
      the right location (reg3) but I need to figure out why it accesses
      beyond what it's supposed to.
      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: Kan Liang <kan.liang@linux.intel.com>
      Cc: Peter Zijlstra <peterz@infradead.org>
      Link: https://lore.kernel.org/r/20240412183310.2518474-2-namhyung@kernel.org
      [ Fix the build on 32-bit by casting Dwarf_Word to (long) in pr_debug_location() ]
      Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
      2bc3cf57
  2. 12 Apr, 2024 29 commits
  3. 08 Apr, 2024 8 commits