Patch "perf dwarf-aux: Check pointer offset when checking variables" has been added to the 6.9-stable tree

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This is a note to let you know that I've just added the patch titled

    perf dwarf-aux: Check pointer offset when checking variables

to the 6.9-stable tree which can be found at:
    http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
     perf-dwarf-aux-check-pointer-offset-when-checking-va.patch
and it can be found in the queue-6.9 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <stable@xxxxxxxxxxxxxxx> know about it.



commit 0eca4590c0f5ec4d89ed9fa6035c3405fc1bfdb9
Author: Namhyung Kim <namhyung@xxxxxxxxxx>
Date:   Fri Apr 12 11:33:08 2024 -0700

    perf dwarf-aux: Check pointer offset when checking variables
    
    [ Upstream commit 645af3fb62bf12911ce1fc79efa676dae9a8289b ]
    
    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:0x7b63c3a)
    
    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: bc10db8eb8955fbc ("perf annotate-data: Support stack variables")
    Signed-off-by: Namhyung Kim <namhyung@xxxxxxxxxx>
    Cc: Adrian Hunter <adrian.hunter@xxxxxxxxx>
    Cc: Ian Rogers <irogers@xxxxxxxxxx>
    Cc: Ingo Molnar <mingo@xxxxxxxxxx>
    Cc: Jiri Olsa <jolsa@xxxxxxxxxx>
    Cc: Kan Liang <kan.liang@xxxxxxxxxxxxxxx>
    Cc: Masami Hiramatsu <mhiramat@xxxxxxxxxx>
    Cc: Namhyung Kim <namhyung@xxxxxxxxxx>
    Cc: Peter Zijlstra <peterz@xxxxxxxxxxxxx>
    Link: https://lore.kernel.org/r/20240412183310.2518474-3-namhyung@xxxxxxxxxx
    Signed-off-by: Arnaldo Carvalho de Melo <acme@xxxxxxxxxx>
    Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>

diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c
index 2791126069b4f..f7f7171539d3c 100644
--- a/tools/perf/util/dwarf-aux.c
+++ b/tools/perf/util/dwarf-aux.c
@@ -1280,7 +1280,7 @@ struct find_var_data {
 #define DWARF_OP_DIRECT_REGS  32
 
 static bool match_var_offset(Dwarf_Die *die_mem, struct find_var_data *data,
-			     u64 addr_offset, u64 addr_type)
+			     u64 addr_offset, u64 addr_type, bool is_pointer)
 {
 	Dwarf_Die type_die;
 	Dwarf_Word size;
@@ -1294,6 +1294,12 @@ static bool match_var_offset(Dwarf_Die *die_mem, struct find_var_data *data,
 	if (die_get_real_type(die_mem, &type_die) == NULL)
 		return false;
 
+	if (is_pointer && dwarf_tag(&type_die) == DW_TAG_pointer_type) {
+		/* Get the target type of the pointer */
+		if (die_get_real_type(&type_die, &type_die) == NULL)
+			return false;
+	}
+
 	if (dwarf_aggregate_size(&type_die, &size) < 0)
 		return false;
 
@@ -1361,31 +1367,38 @@ static int __die_find_var_reg_cb(Dwarf_Die *die_mem, void *arg)
 		if (data->is_fbreg && ops->atom == DW_OP_fbreg &&
 		    data->offset >= (int)ops->number &&
 		    check_allowed_ops(ops, nops) &&
-		    match_var_offset(die_mem, data, data->offset, ops->number))
+		    match_var_offset(die_mem, data, data->offset, ops->number,
+				     /*is_pointer=*/false))
 			return DIE_FIND_CB_END;
 
 		/* Only match with a simple case */
 		if (data->reg < DWARF_OP_DIRECT_REGS) {
 			/* pointer variables saved in a register 0 to 31 */
 			if (ops->atom == (DW_OP_reg0 + data->reg) &&
-			    check_allowed_ops(ops, nops))
+			    check_allowed_ops(ops, nops) &&
+			    match_var_offset(die_mem, data, data->offset, 0,
+					     /*is_pointer=*/true))
 				return DIE_FIND_CB_END;
 
 			/* Local variables accessed by a register + offset */
 			if (ops->atom == (DW_OP_breg0 + data->reg) &&
 			    check_allowed_ops(ops, nops) &&
-			    match_var_offset(die_mem, data, data->offset, ops->number))
+			    match_var_offset(die_mem, data, data->offset, ops->number,
+					     /*is_pointer=*/false))
 				return DIE_FIND_CB_END;
 		} else {
 			/* pointer variables saved in a register 32 or above */
 			if (ops->atom == DW_OP_regx && ops->number == data->reg &&
-			    check_allowed_ops(ops, nops))
+			    check_allowed_ops(ops, nops) &&
+			    match_var_offset(die_mem, data, data->offset, 0,
+					     /*is_pointer=*/true))
 				return DIE_FIND_CB_END;
 
 			/* Local variables accessed by a register + offset */
 			if (ops->atom == DW_OP_bregx && data->reg == ops->number &&
 			    check_allowed_ops(ops, nops) &&
-			    match_var_offset(die_mem, data, data->offset, ops->number2))
+			    match_var_offset(die_mem, data, data->offset, ops->number2,
+					     /*is_poitner=*/false))
 				return DIE_FIND_CB_END;
 		}
 	}
@@ -1447,7 +1460,8 @@ static int __die_find_var_addr_cb(Dwarf_Die *die_mem, void *arg)
 			continue;
 
 		if (check_allowed_ops(ops, nops) &&
-		    match_var_offset(die_mem, data, data->addr, ops->number))
+		    match_var_offset(die_mem, data, data->addr, ops->number,
+				     /*is_pointer=*/false))
 			return DIE_FIND_CB_END;
 	}
 	return DIE_FIND_CB_SIBLING;




[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux