All of lore.kernel.org
 help / color / mirror / Atom feed
From: Arnaldo Carvalho de Melo <acme@kernel.org>
To: Andrii Nakryiko <andrii.nakryiko@gmail.com>
Cc: Jiri Olsa <jolsa@kernel.org>,
	dwarves@vger.kernel.org, bpf <bpf@vger.kernel.org>,
	Alexei Starovoitov <ast@kernel.org>,
	Andrii Nakryiko <andriin@fb.com>, Yonghong Song <yhs@fb.com>,
	Hao Luo <haoluo@google.com>
Subject: Re: [PATCH 3/3] btf_encoder: Detect kernel module ftrace addresses
Date: Mon, 7 Dec 2020 12:54:42 -0300	[thread overview]
Message-ID: <20201207155442.GB125383@kernel.org> (raw)
In-Reply-To: <CAEf4BzYGPxxwaiUnNf4auq=gXzTkBuc=Sz3EJtnbDgaC-BEQ0A@mail.gmail.com>

Em Thu, Dec 03, 2020 at 03:23:57PM -0800, Andrii Nakryiko escreveu:
> On Thu, Dec 3, 2020 at 2:08 PM Jiri Olsa <jolsa@kernel.org> wrote:
> >
> > Add support to detect kernel module ftrace addresses and use
> > it as filter for detected functions.
> >
> > For kernel modules the ftrace addresses are stored in __mcount_loc
> > section. Adding the code that detects this section and reads
> > its data into array, which is then processed as filter by
> > current code.
> >
> > There's one tricky point with kernel modules wrt Elf object,
> > which we get from dwfl_module_getelf function. This function
> > performs all possible relocations, including __mcount_loc
> > section.
> >
> > So addrs array contains relocated values, which we need take
> > into account when we compare them to functions values which
> > are relative to their sections.
> >
> > With this change for example for xfs.ko module in my kernel
> > config, I'm getting slightly bigger number of functions:
> >
> >   before: 2373, after: 2601
> >
> > The ftrace's available_filter_functions still shows 2701, but
> > it includes functions like:
> >
> >   suffix_kstrtoint.constprop.0
> >   xchk_btree_check_minrecs.isra.0
> >   xfs_ascii_ci_compname.part.0
> >
> > which are not part of dwarf data, the rest matches BTF functions.
> >
> > Because of the malfunction DWARF's declaration tag, the 'before'
> > functions contain also functions that are not part of the module.
> > The 'after' functions contain only functions that are traceable
> > and part of xfs.ko.
> >
> > Despite filtering out some declarations, this change also adds
> > static functions, hence the total number of functions is bigger.
> >
> > Signed-off-by: Jiri Olsa <jolsa@kernel.org>
> > ---
> 
> I've tested locally on bpf_testmod that I'm adding to selftests in
> [0]. All worked well. I changed the test function from global to
> non-inlined static, and BTF had it. And the tests passed. So LGTM.
> 
> Tested-by: Andrii Nakryiko <andrii@kernel.org>
> Acked-by: Andrii Nakryiko <andrii@kernel.org>

Thanks, applied the three patches in this series,

- Arnaldo
 
>   [0] https://patchwork.kernel.org/user/todo/netdevbpf/?series=395715&delegate=121173&state=*
> 
> >  btf_encoder.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++++--
> >  dutil.c       |  10 +++++
> >  dutil.h       |   2 +
> >  3 files changed, 109 insertions(+), 3 deletions(-)
> >
> > diff --git a/btf_encoder.c b/btf_encoder.c
> > index 398be0fbf7c7..570fce46b6d9 100644
> > --- a/btf_encoder.c
> > +++ b/btf_encoder.c
> > @@ -36,6 +36,7 @@ struct funcs_layout {
> >  struct elf_function {
> >         const char      *name;
> >         unsigned long    addr;
> > +       unsigned long    sh_addr;
> >         bool             generated;
> >  };
> >
> > @@ -65,11 +66,12 @@ static void delete_functions(void)
> >  static int collect_function(struct btf_elf *btfe, GElf_Sym *sym)
> >  {
> >         struct elf_function *new;
> > +       static GElf_Shdr sh;
> > +       static int last_idx;
> > +       int idx;
> >
> >         if (elf_sym__type(sym) != STT_FUNC)
> >                 return 0;
> > -       if (!elf_sym__value(sym))
> > -               return 0;
> >
> >         if (functions_cnt == functions_alloc) {
> >                 functions_alloc = max(1000, functions_alloc * 3 / 2);
> > @@ -84,8 +86,17 @@ static int collect_function(struct btf_elf *btfe, GElf_Sym *sym)
> >                 functions = new;
> >         }
> >
> > +       idx = elf_sym__section(sym);
> > +
> > +       if (idx != last_idx) {
> > +               if (!elf_section_by_idx(btfe->elf, &sh, idx))
> > +                       return 0;
> > +               last_idx = idx;
> > +       }
> > +
> >         functions[functions_cnt].name = elf_sym__name(sym, btfe->symtab);
> >         functions[functions_cnt].addr = elf_sym__value(sym);
> > +       functions[functions_cnt].sh_addr = sh.sh_addr;
> >         functions[functions_cnt].generated = false;
> >         functions_cnt++;
> >         return 0;
> > @@ -160,10 +171,74 @@ static int get_vmlinux_addrs(struct btf_elf *btfe, struct funcs_layout *fl,
> >         return 0;
> >  }
> >
> > +static int
> > +get_kmod_addrs(struct btf_elf *btfe, __u64 **paddrs, __u64 *pcount)
> > +{
> > +       __u64 *addrs, count;
> > +       unsigned int addr_size, i;
> > +       GElf_Shdr shdr_mcount;
> > +       Elf_Data *data;
> > +       Elf_Scn *sec;
> > +
> > +       /* Initialize for the sake of all error paths below. */
> > +       *paddrs = NULL;
> > +       *pcount = 0;
> > +
> > +       /* get __mcount_loc */
> > +       sec = elf_section_by_name(btfe->elf, &btfe->ehdr, &shdr_mcount,
> > +                                 "__mcount_loc", NULL);
> > +       if (!sec) {
> > +               if (btf_elf__verbose) {
> > +                       printf("%s: '%s' doesn't have __mcount_loc section\n", __func__,
> > +                              btfe->filename);
> > +               }
> > +               return 0;
> > +       }
> > +
> > +       data = elf_getdata(sec, NULL);
> > +       if (!data) {
> > +               fprintf(stderr, "Failed to data for __mcount_loc section.\n");
> > +               return -1;
> > +       }
> > +
> > +       /* Get address size from processed file's ELF class. */
> > +       addr_size = gelf_getclass(btfe->elf) == ELFCLASS32 ? 4 : 8;
> > +
> > +       count = data->d_size / addr_size;
> > +
> > +       addrs = malloc(count * sizeof(addrs[0]));
> > +       if (!addrs) {
> > +               fprintf(stderr, "Failed to allocate memory for ftrace addresses.\n");
> > +               return -1;
> > +       }
> > +
> > +       if (addr_size == sizeof(__u64)) {
> > +               memcpy(addrs, data->d_buf, count * addr_size);
> > +       } else {
> > +               for (i = 0; i < count; i++)
> > +                       addrs[i] = (__u64) *((__u32 *) (data->d_buf + i * addr_size));
> > +       }
> > +
> > +       /*
> > +        * We get Elf object from dwfl_module_getelf function,
> > +        * which performs all possible relocations, including
> > +        * __mcount_loc section.
> > +        *
> > +        * So addrs array now contains relocated values, which
> > +        * we need take into account when we compare them to
> > +        * functions values, see comment in setup_functions
> > +        * function.
> > +        */
> > +       *paddrs = addrs;
> > +       *pcount = count;
> > +       return 0;
> > +}
> > +
> >  static int setup_functions(struct btf_elf *btfe, struct funcs_layout *fl)
> >  {
> >         __u64 *addrs, count, i;
> >         int functions_valid = 0;
> > +       bool kmod = false;
> >
> >         /*
> >          * Check if we are processing vmlinux image and
> > @@ -172,6 +247,16 @@ static int setup_functions(struct btf_elf *btfe, struct funcs_layout *fl)
> >         if (get_vmlinux_addrs(btfe, fl, &addrs, &count))
> >                 return -1;
> >
> > +       /*
> > +        * Check if we are processing kernel module and
> > +        * get mcount data if it's detected.
> > +        */
> > +       if (!addrs) {
> > +               if (get_kmod_addrs(btfe, &addrs, &count))
> > +                       return -1;
> > +               kmod = true;
> > +       }
> > +
> >         if (!addrs) {
> >                 if (btf_elf__verbose)
> >                         printf("ftrace symbols not detected, falling back to DWARF data\n");
> > @@ -188,9 +273,18 @@ static int setup_functions(struct btf_elf *btfe, struct funcs_layout *fl)
> >          */
> >         for (i = 0; i < functions_cnt; i++) {
> >                 struct elf_function *func = &functions[i];
> > +               /*
> > +                * For vmlinux image both addrs[x] and functions[x]::addr
> > +                * values are final address and are comparable.
> > +                *
> > +                * For kernel module addrs[x] is final address, but
> > +                * functions[x]::addr is relative address within section
> > +                * and needs to be relocated by adding sh_addr.
> > +                */
> > +               __u64 addr = kmod ? func->addr + func->sh_addr : func->addr;
> >
> >                 /* Make sure function is within ftrace addresses. */
> > -               if (bsearch(&func->addr, addrs, count, sizeof(addrs[0]), addrs_cmp)) {
> > +               if (bsearch(&addr, addrs, count, sizeof(addrs[0]), addrs_cmp)) {
> >                         /*
> >                          * We iterate over sorted array, so we can easily skip
> >                          * not valid item and move following valid field into
> > diff --git a/dutil.c b/dutil.c
> > index f7b853f0660d..7b667647420f 100644
> > --- a/dutil.c
> > +++ b/dutil.c
> > @@ -196,6 +196,16 @@ Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
> >         return sec;
> >  }
> >
> > +Elf_Scn *elf_section_by_idx(Elf *elf, GElf_Shdr *shp, int idx)
> > +{
> > +       Elf_Scn *sec;
> > +
> > +       sec = elf_getscn(elf, idx);
> > +       if (sec)
> > +               gelf_getshdr(sec, shp);
> > +       return sec;
> > +}
> > +
> >  char *strlwr(char *s)
> >  {
> >         int len = strlen(s), i;
> > diff --git a/dutil.h b/dutil.h
> > index 676770d5d5c9..0838dff2d679 100644
> > --- a/dutil.h
> > +++ b/dutil.h
> > @@ -324,6 +324,8 @@ void *zalloc(const size_t size);
> >  Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
> >                              GElf_Shdr *shp, const char *name, size_t *index);
> >
> > +Elf_Scn *elf_section_by_idx(Elf *elf, GElf_Shdr *shp, int idx);
> > +
> >  #ifndef SHT_GNU_ATTRIBUTES
> >  /* Just a way to check if we're using an old elfutils version */
> >  static inline int elf_getshdrstrndx(Elf *elf, size_t *dst)
> > --
> > 2.26.2
> >

-- 

- Arnaldo

      reply	other threads:[~2020-12-07 15:55 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-12-03 22:06 [PATCHv2 0/3] btf_encoder: Detect kernel modules Jiri Olsa
2020-12-03 22:06 ` [PATCH 1/3] btf_encoder: Factor filter_functions function Jiri Olsa
2020-12-03 23:20   ` Andrii Nakryiko
2020-12-03 22:06 ` [PATCH 2/3] btf_encoder: Use address size based on ELF's class Jiri Olsa
2020-12-03 23:22   ` Andrii Nakryiko
2020-12-03 23:37     ` Jiri Olsa
2020-12-07 15:45       ` Arnaldo Carvalho de Melo
2020-12-03 22:06 ` [PATCH 3/3] btf_encoder: Detect kernel module ftrace addresses Jiri Olsa
2020-12-03 23:23   ` Andrii Nakryiko
2020-12-07 15:54     ` Arnaldo Carvalho de Melo [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20201207155442.GB125383@kernel.org \
    --to=acme@kernel.org \
    --cc=andrii.nakryiko@gmail.com \
    --cc=andriin@fb.com \
    --cc=ast@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=dwarves@vger.kernel.org \
    --cc=haoluo@google.com \
    --cc=jolsa@kernel.org \
    --cc=yhs@fb.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.