[PATCH dwarves v2 4/9] dwarf_laoder: Handle locations with DW_OP_fbreg

Yonghong Song <[email protected]>
Newsgroups org.kernel.vger.dwarves,org.kernel.vger.bpf
Message-ID <[email protected]>
DW_OP_fbreg means the parameter value will be stored on the
stack. So the corresponding parameter register is not used.
For example:

  0x071f7717:   DW_TAG_subprogram
                  DW_AT_name      ("jent_health_failure")
                  DW_AT_calling_convention        (DW_CC_nocall)
                  DW_AT_type      (0x071f7626 "unsigned int")
                  ...

  0x071f7728:     DW_TAG_formal_parameter
                    DW_AT_location        (DW_OP_fbreg -8)
                    DW_AT_name    ("ec")
                    DW_AT_type    (0x071f7ab6 "rand_data *")
                    ...

  0x071f7734:     NULL

In the above, the parameter 'ec' type is a pointer so it perfectly fits
into a register. But the location uses 'DW_OP_fbreg -8' which prevents
from generating a function with true signatures.

Signed-off-by: Yonghong Song <[email protected]>
---
 dwarf_loader.c | 17 ++++++++++++++---
 1 file changed, 14 insertions(+), 3 deletions(-)

diff --git a/dwarf_loader.c b/dwarf_loader.c
index 7da3926..d538607 100644
--- a/dwarf_loader.c
+++ b/dwarf_loader.c
@@ -1196,6 +1196,7 @@ struct func_info {
 };
 
 #define	PARM_DEFAULT_FAIL	-1
+#define	PARM_FAIL_CLANG		-2
 
 /* For DW_AT_location 'attr':
  * - if first location is DW_OP_regXX with expected number, return the register;
@@ -1204,7 +1205,7 @@ struct func_info {
  *   list, return the register; otherwise save register for later return
  * - otherwise if no register was found for locations, return PARM_DEFAULT_FAIL.
  */
-static int parameter__reg(Dwarf_Attribute *attr, int expected_reg)
+static int parameter__reg(Dwarf_Attribute *attr, int expected_reg, struct cu *cu, struct conf_load *conf)
 {
 	Dwarf_Addr base, start, end;
 	Dwarf_Op *expr, *entry_ops;
@@ -1240,6 +1241,16 @@ static int parameter__reg(Dwarf_Attribute *attr, int expected_reg)
 			if (ret == expected_reg)
 				goto out;
 			break;
+		case DW_OP_fbreg:
+			/* The locaiton like
+			 *   DW_AT_location        (DW_OP_fbreg +<num>)
+			 * indicates that the parameter is on the stack. But it is possible
+			 * that the parameter can fit in register(s). So conservatively
+			 * mark this parameter not suitable for true signatures.
+			 */
+			if (cu->producer_clang && conf->true_signature)
+				ret = PARM_FAIL_CLANG;
+			break;
 		/* match DW_OP_entry_value(DW_OP_regXX) at any location */
 		case DW_OP_entry_value:
 		case DW_OP_GNU_entry_value:
@@ -1328,11 +1339,11 @@ static struct parameter *parameter__new(Dwarf_Die *die, struct cu *cu,
 
 		if (parm->has_loc) {
 			int expected_reg = cu->register_params[reg_idx];
-			int actual_reg = parameter__reg(&attr, expected_reg);
+			int actual_reg = parameter__reg(&attr, expected_reg, cu, conf);
 
 			if (actual_reg == PARM_DEFAULT_FAIL)
 				parm->optimized = 1;
-			else if (expected_reg >= 0 && expected_reg != actual_reg)
+			else if (actual_reg == PARM_FAIL_CLANG || (expected_reg >= 0 && expected_reg != actual_reg))
 				/* mark parameters that use an unexpected
 				 * register to hold a parameter; these will
 				 * be problematic for users of BTF as they
-- 
2.47.3
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.