lkml.org 
[lkml]   [2023]   [Oct]   [11]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 28/48] perf dwarf-aux: Add die_find_variable_by_addr()
    Date
    The die_find_variable_by_addr() is to find a variables in the given DIE
    using given (PC-relative) address. Global variables will have a
    location expression with DW_OP_addr which has an address so can simply
    compare it with the address.

    <1><143a7>: Abbrev Number: 2 (DW_TAG_variable)
    <143a8> DW_AT_name : loops_per_jiffy
    <143ac> DW_AT_type : <0x1cca>
    <143b0> DW_AT_external : 1
    <143b0> DW_AT_decl_file : 193
    <143b1> DW_AT_decl_line : 213
    <143b2> DW_AT_location : 9 byte block: 3 b0 46 41 82 ff ff ff ff
    (DW_OP_addr: ffffffff824146b0)

    Note that the type-offset should be calculated from the base address of
    the global variable.

    Signed-off-by: Namhyung Kim <namhyung@kernel.org>
    ---
    tools/perf/util/dwarf-aux.c | 80 +++++++++++++++++++++++++++++++++++++
    tools/perf/util/dwarf-aux.h | 14 +++++++
    2 files changed, 94 insertions(+)

    diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c
    index 5bb05c84d249..97d9ae56350e 100644
    --- a/tools/perf/util/dwarf-aux.c
    +++ b/tools/perf/util/dwarf-aux.c
    @@ -1266,8 +1266,12 @@ int die_get_var_range(Dwarf_Die *sp_die, Dwarf_Die *vr_die, struct strbuf *buf)
    struct find_var_data {
    /* Target instruction address */
    Dwarf_Addr pc;
    + /* Target memory address (for global data) */
    + Dwarf_Addr addr;
    /* Target register */
    unsigned reg;
    + /* Access offset, set for global data */
    + int offset;
    };

    /* Max number of registers DW_OP_regN supports */
    @@ -1328,6 +1332,82 @@ Dwarf_Die *die_find_variable_by_reg(Dwarf_Die *sc_die, Dwarf_Addr pc, int reg,
    };
    return die_find_child(sc_die, __die_find_var_reg_cb, &data, die_mem);
    }
    +
    +/* Only checks direct child DIEs in the given scope */
    +static int __die_find_var_addr_cb(Dwarf_Die *die_mem, void *arg)
    +{
    + struct find_var_data *data = arg;
    + int tag = dwarf_tag(die_mem);
    + ptrdiff_t off = 0;
    + Dwarf_Attribute attr;
    + Dwarf_Addr base, start, end;
    + Dwarf_Word size;
    + Dwarf_Die type_die;
    + Dwarf_Op *ops;
    + size_t nops;
    +
    + if (tag != DW_TAG_variable)
    + return DIE_FIND_CB_SIBLING;
    +
    + if (dwarf_attr(die_mem, DW_AT_location, &attr) == NULL)
    + return DIE_FIND_CB_SIBLING;
    +
    + while ((off = dwarf_getlocations(&attr, off, &base, &start, &end, &ops, &nops)) > 0) {
    + if (ops->atom != DW_OP_addr)
    + continue;
    +
    + if (data->addr < ops->number)
    + continue;
    +
    + if (data->addr == ops->number) {
    + /* Update offset relative to the start of the variable */
    + data->offset = 0;
    + return DIE_FIND_CB_END;
    + }
    +
    + if (die_get_real_type(die_mem, &type_die) == NULL)
    + continue;
    +
    + if (dwarf_aggregate_size(&type_die, &size) < 0)
    + continue;
    +
    + if (data->addr >= ops->number + size)
    + continue;
    +
    + /* Update offset relative to the start of the variable */
    + data->offset = data->addr - ops->number;
    + return DIE_FIND_CB_END;
    + }
    + return DIE_FIND_CB_SIBLING;
    +}
    +
    +/**
    + * die_find_variable_by_addr - Find variable located at given address
    + * @sc_die: a scope DIE
    + * @pc: the program address to find
    + * @addr: the data address to find
    + * @die_mem: a buffer to save the resulting DIE
    + * @offset: the offset in the resulting type
    + *
    + * Find the variable DIE located at the given address (in PC-relative mode).
    + * This is usually for global variables.
    + */
    +Dwarf_Die *die_find_variable_by_addr(Dwarf_Die *sc_die, Dwarf_Addr pc,
    + Dwarf_Addr addr, Dwarf_Die *die_mem,
    + int *offset)
    +{
    + struct find_var_data data = {
    + .pc = pc,
    + .addr = addr,
    + };
    + Dwarf_Die *result;
    +
    + result = die_find_child(sc_die, __die_find_var_addr_cb, &data, die_mem);
    + if (result)
    + *offset = data.offset;
    + return result;
    +}
    +
    #endif

    /*
    diff --git a/tools/perf/util/dwarf-aux.h b/tools/perf/util/dwarf-aux.h
    index 574405c57d3b..742098e3ee7e 100644
    --- a/tools/perf/util/dwarf-aux.h
    +++ b/tools/perf/util/dwarf-aux.h
    @@ -144,6 +144,11 @@ int die_get_var_range(Dwarf_Die *sp_die, Dwarf_Die *vr_die, struct strbuf *buf);
    Dwarf_Die *die_find_variable_by_reg(Dwarf_Die *sc_die, Dwarf_Addr pc, int reg,
    Dwarf_Die *die_mem);

    +/* Find a (global) variable located in the 'addr' */
    +Dwarf_Die *die_find_variable_by_addr(Dwarf_Die *sc_die, Dwarf_Addr pc,
    + Dwarf_Addr addr, Dwarf_Die *die_mem,
    + int *offset);
    +
    #else /* HAVE_DWARF_GETLOCATIONS_SUPPORT */

    static inline int die_get_var_range(Dwarf_Die *sp_die __maybe_unused,
    @@ -161,6 +166,15 @@ static inline Dwarf_Die *die_find_variable_by_reg(Dwarf_Die *sc_die __maybe_unus
    return NULL;
    }

    +static inline Dwarf_Die *die_find_variable_by_addr(Dwarf_Die *sc_die __maybe_unused,
    + Dwarf_Addr pc __maybe_unused,
    + Dwarf_Addr addr __maybe_unused,
    + Dwarf_Die *die_mem __maybe_unused,
    + int *offset __maybe_unused)
    +{
    + return NULL;
    +}
    +
    #endif /* HAVE_DWARF_GETLOCATIONS_SUPPORT */

    #endif /* _DWARF_AUX_H */
    --
    2.42.0.655.g421f12c284-goog
    \
     
     \ /
      Last update: 2023-10-12 05:56    [W:4.036 / U:0.516 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site