/* Show a location */ static int convert_location(Dwarf_Op *op, struct probe_finder *pf) { unsigned int regn; Dwarf_Word offs = 0; bool ref = false; const char *regs; struct kprobe_trace_arg *tvar = pf->tvar; /* If this is based on frame buffer, set the offset */ if (op->atom == DW_OP_fbreg) { if (pf->fb_ops == NULL) { pr_warning("The attribute of frame base is not " "supported.\n"); return -ENOTSUP; } ref = true; offs = op->number; op = &pf->fb_ops[0]; } if (op->atom >= DW_OP_breg0 && op->atom <= DW_OP_breg31) { regn = op->atom - DW_OP_breg0; offs += op->number; ref = true; } else if (op->atom >= DW_OP_reg0 && op->atom <= DW_OP_reg31) { regn = op->atom - DW_OP_reg0; } else if (op->atom == DW_OP_bregx) { regn = op->number; offs += op->number2; ref = true; } else if (op->atom == DW_OP_regx) { regn = op->number; } else { pr_warning("DW_OP %x is not supported.\n", op->atom); return -ENOTSUP; } regs = get_arch_regstr(regn); if (!regs) { pr_warning("Mapping for DWARF register number %u missing on this architecture.", regn); return -ERANGE; } tvar->value = strdup(regs); if (tvar->value == NULL) return -ENOMEM; if (ref) { tvar->ref = zalloc(sizeof(struct kprobe_trace_arg_ref)); if (tvar->ref == NULL) return -ENOMEM; tvar->ref->offset = (long)offs; } return 0; }
static int convert_variable_location(Dwarf_Die *vr_die, Dwarf_Addr addr, Dwarf_Op *fb_ops, struct probe_trace_arg *tvar) { Dwarf_Attribute attr; Dwarf_Op *op; size_t nops; unsigned int regn; Dwarf_Word offs = 0; bool ref = false; const char *regs; int ret; if (dwarf_attr(vr_die, DW_AT_external, &attr) != NULL) goto static_var; if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL || dwarf_getlocation_addr(&attr, addr, &op, &nops, 1) <= 0 || nops == 0) { return -ENOENT; } if (op->atom == DW_OP_addr) { static_var: if (!tvar) return 0; ret = strlen(dwarf_diename(vr_die)); tvar->value = zalloc(ret + 2); if (tvar->value == NULL) return -ENOMEM; snprintf(tvar->value, ret + 2, "@%s", dwarf_diename(vr_die)); tvar->ref = alloc_trace_arg_ref((long)offs); if (tvar->ref == NULL) return -ENOMEM; return 0; } if (op->atom == DW_OP_fbreg) { if (fb_ops == NULL) return -ENOTSUP; ref = true; offs = op->number; op = &fb_ops[0]; } if (op->atom >= DW_OP_breg0 && op->atom <= DW_OP_breg31) { regn = op->atom - DW_OP_breg0; offs += op->number; ref = true; } else if (op->atom >= DW_OP_reg0 && op->atom <= DW_OP_reg31) { regn = op->atom - DW_OP_reg0; } else if (op->atom == DW_OP_bregx) { regn = op->number; offs += op->number2; ref = true; } else if (op->atom == DW_OP_regx) { regn = op->number; } else { pr_debug("DW_OP %x is not supported.\n", op->atom); return -ENOTSUP; } if (!tvar) return 0; regs = get_arch_regstr(regn); if (!regs) { pr_warning("Mapping for the register number %u " "missing on this architecture.\n", regn); return -ERANGE; } tvar->value = strdup(regs); if (tvar->value == NULL) return -ENOMEM; if (ref) { tvar->ref = alloc_trace_arg_ref((long)offs); if (tvar->ref == NULL) return -ENOMEM; } return 0; }
/* * Convert a location into trace_arg. * If tvar == NULL, this just checks variable can be converted. * If fentry == true and vr_die is a parameter, do huristic search * for the location fuzzed by function entry mcount. */ static int convert_variable_location(Dwarf_Die *vr_die, Dwarf_Addr addr, Dwarf_Op *fb_ops, Dwarf_Die *sp_die, struct probe_trace_arg *tvar) { Dwarf_Attribute attr; Dwarf_Addr tmp = 0; Dwarf_Op *op; size_t nops; unsigned int regn; Dwarf_Word offs = 0; bool ref = false; const char *regs; int ret; if (dwarf_attr(vr_die, DW_AT_external, &attr) != NULL) goto static_var; /* TODO: handle more than 1 exprs */ if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL) return -EINVAL; /* Broken DIE ? */ if (dwarf_getlocation_addr(&attr, addr, &op, &nops, 1) <= 0) { ret = dwarf_entrypc(sp_die, &tmp); if (ret || addr != tmp || dwarf_tag(vr_die) != DW_TAG_formal_parameter || dwarf_highpc(sp_die, &tmp)) return -ENOENT; /* * This is fuzzed by fentry mcount. We try to find the * parameter location at the earliest address. */ for (addr += 1; addr <= tmp; addr++) { if (dwarf_getlocation_addr(&attr, addr, &op, &nops, 1) > 0) goto found; } return -ENOENT; } found: if (nops == 0) /* TODO: Support const_value */ return -ENOENT; if (op->atom == DW_OP_addr) { static_var: if (!tvar) return 0; /* Static variables on memory (not stack), make @varname */ ret = strlen(dwarf_diename(vr_die)); tvar->value = zalloc(ret + 2); if (tvar->value == NULL) return -ENOMEM; snprintf(tvar->value, ret + 2, "@%s", dwarf_diename(vr_die)); tvar->ref = alloc_trace_arg_ref((long)offs); if (tvar->ref == NULL) return -ENOMEM; return 0; } /* If this is based on frame buffer, set the offset */ if (op->atom == DW_OP_fbreg) { if (fb_ops == NULL) return -ENOTSUP; ref = true; offs = op->number; op = &fb_ops[0]; } if (op->atom >= DW_OP_breg0 && op->atom <= DW_OP_breg31) { regn = op->atom - DW_OP_breg0; offs += op->number; ref = true; } else if (op->atom >= DW_OP_reg0 && op->atom <= DW_OP_reg31) { regn = op->atom - DW_OP_reg0; } else if (op->atom == DW_OP_bregx) { regn = op->number; offs += op->number2; ref = true; } else if (op->atom == DW_OP_regx) { regn = op->number; } else { pr_debug("DW_OP %x is not supported.\n", op->atom); return -ENOTSUP; } if (!tvar) return 0; regs = get_arch_regstr(regn); if (!regs) { /* This should be a bug in DWARF or this tool */ pr_warning("Mapping for the register number %u " "missing on this architecture.\n", regn); return -ERANGE; } tvar->value = strdup(regs); if (tvar->value == NULL) return -ENOMEM; if (ref) { tvar->ref = alloc_trace_arg_ref((long)offs); if (tvar->ref == NULL) return -ENOMEM; } return 0; }