* [RFC 0/2] btf_encoder: Detect kernel modules @ 2020-11-24 16:19 Jiri Olsa 2020-11-24 16:19 ` [PATCH 1/2] btf_encoder: Factor filter_functions function Jiri Olsa 2020-11-24 16:19 ` [PATCH 2/2] btf_encoder: Detect kernel module ftrace addresses Jiri Olsa 0 siblings, 2 replies; 8+ messages in thread From: Jiri Olsa @ 2020-11-24 16:19 UTC (permalink / raw) To: Arnaldo Carvalho de Melo Cc: dwarves, bpf, Alexei Starovoitov, Andrii Nakryiko, Yonghong Song, Hao Luo hi, adding support to detect kernel module and use its mcount_loc section data as function filter. It's working on my setup, but I fear there might be kernel configuration where it could fail. I'm mostly worried about the assumption that there's always relocation section '.rela__mcount_loc' for '__mcount_loc' section in kernel modules. And because the relocation changes addresses, we need to be sure we compare relative or relocated addresses. I still need to double check scripts/recordmcount.c to be sure about that. Any testing feedback would be great. thanks, jirka --- Jiri Olsa (2): btf_encoder: Factor filter_functions function btf_encoder: Detect kernel module ftrace addresses btf_encoder.c | 142 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------- dutil.c | 16 ++++++++++++++++ dutil.h | 2 ++ 3 files changed, 137 insertions(+), 23 deletions(-) ^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 1/2] btf_encoder: Factor filter_functions function 2020-11-24 16:19 [RFC 0/2] btf_encoder: Detect kernel modules Jiri Olsa @ 2020-11-24 16:19 ` Jiri Olsa 2020-11-27 4:05 ` Andrii Nakryiko 2020-11-24 16:19 ` [PATCH 2/2] btf_encoder: Detect kernel module ftrace addresses Jiri Olsa 1 sibling, 1 reply; 8+ messages in thread From: Jiri Olsa @ 2020-11-24 16:19 UTC (permalink / raw) To: Arnaldo Carvalho de Melo Cc: dwarves, bpf, Alexei Starovoitov, Andrii Nakryiko, Yonghong Song, Hao Luo Reorder the filter_functions function so we can add processing of kernel modules in following patch. There's no functional change intended. Signed-off-by: Jiri Olsa <jolsa@kernel.org> --- btf_encoder.c | 57 +++++++++++++++++++++++++++++++++------------------ 1 file changed, 37 insertions(+), 20 deletions(-) diff --git a/btf_encoder.c b/btf_encoder.c index c40f059580da..467c4657b2c0 100644 --- a/btf_encoder.c +++ b/btf_encoder.c @@ -101,14 +101,17 @@ static int addrs_cmp(const void *_a, const void *_b) return *a < *b ? -1 : 1; } -static int filter_functions(struct btf_elf *btfe, struct funcs_layout *fl) +static int get_vmlinux_addrs(struct btf_elf *btfe, struct funcs_layout *fl, + unsigned long **paddrs, unsigned long *pcount) { - unsigned long *addrs, count, offset, i; - int functions_valid = 0; + unsigned long *addrs, count, offset; Elf_Data *data; GElf_Shdr shdr; Elf_Scn *sec; + if (!fl->mcount_start || !fl->mcount_stop) + return 0; + /* * Find mcount addressed marked by __start_mcount_loc * and __stop_mcount_loc symbols and load them into @@ -138,7 +141,32 @@ static int filter_functions(struct btf_elf *btfe, struct funcs_layout *fl) } memcpy(addrs, data->d_buf + offset, count * sizeof(addrs[0])); + *paddrs = addrs; + *pcount = count; + return 0; +} + +static int setup_functions(struct btf_elf *btfe, struct funcs_layout *fl) +{ + unsigned long *addrs = NULL, count, i; + int functions_valid = 0; + + /* + * Check if we are processing vmlinux image and + * get mcount data if it's detected. + */ + if (get_vmlinux_addrs(btfe, fl, &addrs, &count)) + return -1; + + if (!addrs) { + if (btf_elf__verbose) + printf("ftrace symbols not detected, falling back to DWARF data\n"); + delete_functions(); + return 0; + } + qsort(addrs, count, sizeof(addrs[0]), addrs_cmp); + qsort(functions, functions_cnt, sizeof(functions[0]), functions_cmp); /* * Let's got through all collected functions and filter @@ -162,6 +190,9 @@ static int filter_functions(struct btf_elf *btfe, struct funcs_layout *fl) functions_cnt = functions_valid; free(addrs); + + if (btf_elf__verbose) + printf("Found %d functions!\n", functions_cnt); return 0; } @@ -470,11 +501,6 @@ static void collect_symbol(GElf_Sym *sym, struct funcs_layout *fl) fl->mcount_stop = sym->st_value; } -static int has_all_symbols(struct funcs_layout *fl) -{ - return fl->mcount_start && fl->mcount_stop; -} - static int collect_symbols(struct btf_elf *btfe, bool collect_percpu_vars) { struct funcs_layout fl = { }; @@ -501,18 +527,9 @@ static int collect_symbols(struct btf_elf *btfe, bool collect_percpu_vars) printf("Found %d per-CPU variables!\n", percpu_var_cnt); } - if (functions_cnt && has_all_symbols(&fl)) { - qsort(functions, functions_cnt, sizeof(functions[0]), functions_cmp); - if (filter_functions(btfe, &fl)) { - fprintf(stderr, "Failed to filter dwarf functions\n"); - return -1; - } - if (btf_elf__verbose) - printf("Found %d functions!\n", functions_cnt); - } else { - if (btf_elf__verbose) - printf("ftrace symbols not detected, falling back to DWARF data\n"); - delete_functions(); + if (functions_cnt && setup_functions(btfe, &fl)) { + fprintf(stderr, "Failed to filter dwarf functions\n"); + return -1; } return 0; -- 2.26.2 ^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH 1/2] btf_encoder: Factor filter_functions function 2020-11-24 16:19 ` [PATCH 1/2] btf_encoder: Factor filter_functions function Jiri Olsa @ 2020-11-27 4:05 ` Andrii Nakryiko 2020-11-27 17:21 ` Jiri Olsa 0 siblings, 1 reply; 8+ messages in thread From: Andrii Nakryiko @ 2020-11-27 4:05 UTC (permalink / raw) To: Jiri Olsa Cc: Arnaldo Carvalho de Melo, dwarves, bpf, Alexei Starovoitov, Andrii Nakryiko, Yonghong Song, Hao Luo On Tue, Nov 24, 2020 at 8:22 AM Jiri Olsa <jolsa@kernel.org> wrote: > > Reorder the filter_functions function so we can add > processing of kernel modules in following patch. > > There's no functional change intended. > > Signed-off-by: Jiri Olsa <jolsa@kernel.org> > --- > btf_encoder.c | 57 +++++++++++++++++++++++++++++++++------------------ > 1 file changed, 37 insertions(+), 20 deletions(-) > > diff --git a/btf_encoder.c b/btf_encoder.c > index c40f059580da..467c4657b2c0 100644 > --- a/btf_encoder.c > +++ b/btf_encoder.c > @@ -101,14 +101,17 @@ static int addrs_cmp(const void *_a, const void *_b) > return *a < *b ? -1 : 1; > } > > -static int filter_functions(struct btf_elf *btfe, struct funcs_layout *fl) > +static int get_vmlinux_addrs(struct btf_elf *btfe, struct funcs_layout *fl, > + unsigned long **paddrs, unsigned long *pcount) > { > - unsigned long *addrs, count, offset, i; > - int functions_valid = 0; > + unsigned long *addrs, count, offset; > Elf_Data *data; > GElf_Shdr shdr; > Elf_Scn *sec; > > + if (!fl->mcount_start || !fl->mcount_stop) > + return 0; > + probably better to explicitly assign paddrs and pcount to NULL and 0 here > /* > * Find mcount addressed marked by __start_mcount_loc > * and __stop_mcount_loc symbols and load them into > @@ -138,7 +141,32 @@ static int filter_functions(struct btf_elf *btfe, struct funcs_layout *fl) > } > > memcpy(addrs, data->d_buf + offset, count * sizeof(addrs[0])); > + *paddrs = addrs; > + *pcount = count; > + return 0; > +} > + > +static int setup_functions(struct btf_elf *btfe, struct funcs_layout *fl) > +{ > + unsigned long *addrs = NULL, count, i; > + int functions_valid = 0; > + > + /* > + * Check if we are processing vmlinux image and > + * get mcount data if it's detected. > + */ > + if (get_vmlinux_addrs(btfe, fl, &addrs, &count)) > + return -1; > + > + if (!addrs) { > + if (btf_elf__verbose) > + printf("ftrace symbols not detected, falling back to DWARF data\n"); > + delete_functions(); > + return 0; > + } > + > qsort(addrs, count, sizeof(addrs[0]), addrs_cmp); > + qsort(functions, functions_cnt, sizeof(functions[0]), functions_cmp); > > /* > * Let's got through all collected functions and filter > @@ -162,6 +190,9 @@ static int filter_functions(struct btf_elf *btfe, struct funcs_layout *fl) > > functions_cnt = functions_valid; > free(addrs); > + > + if (btf_elf__verbose) > + printf("Found %d functions!\n", functions_cnt); > return 0; > } > > @@ -470,11 +501,6 @@ static void collect_symbol(GElf_Sym *sym, struct funcs_layout *fl) > fl->mcount_stop = sym->st_value; > } > > -static int has_all_symbols(struct funcs_layout *fl) > -{ > - return fl->mcount_start && fl->mcount_stop; > -} > - > static int collect_symbols(struct btf_elf *btfe, bool collect_percpu_vars) > { > struct funcs_layout fl = { }; > @@ -501,18 +527,9 @@ static int collect_symbols(struct btf_elf *btfe, bool collect_percpu_vars) > printf("Found %d per-CPU variables!\n", percpu_var_cnt); > } > > - if (functions_cnt && has_all_symbols(&fl)) { > - qsort(functions, functions_cnt, sizeof(functions[0]), functions_cmp); > - if (filter_functions(btfe, &fl)) { > - fprintf(stderr, "Failed to filter dwarf functions\n"); > - return -1; > - } > - if (btf_elf__verbose) > - printf("Found %d functions!\n", functions_cnt); > - } else { > - if (btf_elf__verbose) > - printf("ftrace symbols not detected, falling back to DWARF data\n"); > - delete_functions(); > + if (functions_cnt && setup_functions(btfe, &fl)) { > + fprintf(stderr, "Failed to filter dwarf functions\n"); DWARF > + return -1; > } > > return 0; > -- > 2.26.2 > ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 1/2] btf_encoder: Factor filter_functions function 2020-11-27 4:05 ` Andrii Nakryiko @ 2020-11-27 17:21 ` Jiri Olsa 0 siblings, 0 replies; 8+ messages in thread From: Jiri Olsa @ 2020-11-27 17:21 UTC (permalink / raw) To: Andrii Nakryiko Cc: Jiri Olsa, Arnaldo Carvalho de Melo, dwarves, bpf, Alexei Starovoitov, Andrii Nakryiko, Yonghong Song, Hao Luo On Thu, Nov 26, 2020 at 08:05:11PM -0800, Andrii Nakryiko wrote: > On Tue, Nov 24, 2020 at 8:22 AM Jiri Olsa <jolsa@kernel.org> wrote: > > > > Reorder the filter_functions function so we can add > > processing of kernel modules in following patch. > > > > There's no functional change intended. > > > > Signed-off-by: Jiri Olsa <jolsa@kernel.org> > > --- > > btf_encoder.c | 57 +++++++++++++++++++++++++++++++++------------------ > > 1 file changed, 37 insertions(+), 20 deletions(-) > > > > diff --git a/btf_encoder.c b/btf_encoder.c > > index c40f059580da..467c4657b2c0 100644 > > --- a/btf_encoder.c > > +++ b/btf_encoder.c > > @@ -101,14 +101,17 @@ static int addrs_cmp(const void *_a, const void *_b) > > return *a < *b ? -1 : 1; > > } > > > > -static int filter_functions(struct btf_elf *btfe, struct funcs_layout *fl) > > +static int get_vmlinux_addrs(struct btf_elf *btfe, struct funcs_layout *fl, > > + unsigned long **paddrs, unsigned long *pcount) > > { > > - unsigned long *addrs, count, offset, i; > > - int functions_valid = 0; > > + unsigned long *addrs, count, offset; > > Elf_Data *data; > > GElf_Shdr shdr; > > Elf_Scn *sec; > > > > + if (!fl->mcount_start || !fl->mcount_stop) > > + return 0; > > + > > probably better to explicitly assign paddrs and pcount to NULL and 0 here ok SNIP > > - if (functions_cnt && has_all_symbols(&fl)) { > > - qsort(functions, functions_cnt, sizeof(functions[0]), functions_cmp); > > - if (filter_functions(btfe, &fl)) { > > - fprintf(stderr, "Failed to filter dwarf functions\n"); > > - return -1; > > - } > > - if (btf_elf__verbose) > > - printf("Found %d functions!\n", functions_cnt); > > - } else { > > - if (btf_elf__verbose) > > - printf("ftrace symbols not detected, falling back to DWARF data\n"); > > - delete_functions(); > > + if (functions_cnt && setup_functions(btfe, &fl)) { > > + fprintf(stderr, "Failed to filter dwarf functions\n"); > > DWARF ook thanks, jirka ^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 2/2] btf_encoder: Detect kernel module ftrace addresses 2020-11-24 16:19 [RFC 0/2] btf_encoder: Detect kernel modules Jiri Olsa 2020-11-24 16:19 ` [PATCH 1/2] btf_encoder: Factor filter_functions function Jiri Olsa @ 2020-11-24 16:19 ` Jiri Olsa 2020-11-27 4:18 ` Andrii Nakryiko 1 sibling, 1 reply; 8+ messages in thread From: Jiri Olsa @ 2020-11-24 16:19 UTC (permalink / raw) To: Arnaldo Carvalho de Melo Cc: dwarves, bpf, Alexei Starovoitov, Andrii Nakryiko, Yonghong Song, Hao Luo Add support to detect kernel module dtrace addresses and use it as filter for 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: 2429, after: 2615 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> --- btf_encoder.c | 85 +++++++++++++++++++++++++++++++++++++++++++++++++-- dutil.c | 16 ++++++++++ dutil.h | 2 ++ 3 files changed, 100 insertions(+), 3 deletions(-) diff --git a/btf_encoder.c b/btf_encoder.c index 467c4657b2c0..e6114c10ad01 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,11 @@ 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; 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 +85,17 @@ static int collect_function(struct btf_elf *btfe, GElf_Sym *sym) functions = new; } + if (elf_sym__section(sym) != last_idx) { + int idx = elf_sym__section(sym); + + 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; @@ -146,10 +156,60 @@ static int get_vmlinux_addrs(struct btf_elf *btfe, struct funcs_layout *fl, return 0; } +static int +get_kmod_addrs(struct btf_elf *btfe, unsigned long **paddrs, unsigned long *pcount) +{ + unsigned long *addrs, count; + GElf_Shdr shdr_mcount; + Elf_Data *data; + Elf_Scn *sec; + + /* 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; + } + + addrs = malloc(data->d_size); + if (!addrs) { + fprintf(stderr, "Failed to allocate memory for ftrace addresses.\n"); + return -1; + } + + count = data->d_size / sizeof(unsigned long); + memcpy(addrs, data->d_buf, data->d_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) { unsigned long *addrs = NULL, count, i; int functions_valid = 0; + bool kmod = false; /* * Check if we are processing vmlinux image and @@ -158,6 +218,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"); @@ -174,9 +244,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. + */ + unsigned long 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..5ebbd2f9c84c 100644 --- a/dutil.c +++ b/dutil.c @@ -196,6 +196,22 @@ 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 = NULL; + size_t cnt = 1; + + while ((sec = elf_nextscn(elf, sec)) != NULL) { + if (cnt == idx) { + gelf_getshdr(sec, shp); + return sec; + } + ++cnt; + } + + return NULL; +} + 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 ^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH 2/2] btf_encoder: Detect kernel module ftrace addresses 2020-11-24 16:19 ` [PATCH 2/2] btf_encoder: Detect kernel module ftrace addresses Jiri Olsa @ 2020-11-27 4:18 ` Andrii Nakryiko 2020-11-27 17:40 ` Jiri Olsa 0 siblings, 1 reply; 8+ messages in thread From: Andrii Nakryiko @ 2020-11-27 4:18 UTC (permalink / raw) To: Jiri Olsa Cc: Arnaldo Carvalho de Melo, dwarves, bpf, Alexei Starovoitov, Andrii Nakryiko, Yonghong Song, Hao Luo On Tue, Nov 24, 2020 at 8:22 AM Jiri Olsa <jolsa@kernel.org> wrote: > > Add support to detect kernel module dtrace addresses and use > it as filter for functions. typo: dtrace -> ftrace? > > 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: 2429, after: 2615 > > 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> > --- > btf_encoder.c | 85 +++++++++++++++++++++++++++++++++++++++++++++++++-- > dutil.c | 16 ++++++++++ > dutil.h | 2 ++ > 3 files changed, 100 insertions(+), 3 deletions(-) > > diff --git a/btf_encoder.c b/btf_encoder.c > index 467c4657b2c0..e6114c10ad01 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,11 @@ 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; > > 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 +85,17 @@ static int collect_function(struct btf_elf *btfe, GElf_Sym *sym) > functions = new; > } > > + if (elf_sym__section(sym) != last_idx) { > + int idx = elf_sym__section(sym); nit: elf_sym__section() called twice, maybe have sec_idx local variable instead? > + > + if (!elf_section_by_idx(btfe->elf, &sh, idx)) > + return 0; isn't this an error and shouldn't 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; > @@ -146,10 +156,60 @@ static int get_vmlinux_addrs(struct btf_elf *btfe, struct funcs_layout *fl, > return 0; > } > > +static int > +get_kmod_addrs(struct btf_elf *btfe, unsigned long **paddrs, unsigned long *pcount) > +{ > + unsigned long *addrs, count; > + GElf_Shdr shdr_mcount; > + Elf_Data *data; > + Elf_Scn *sec; > + > + /* 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); > + } nit: unnecessary {} for single-statement if > + return 0; > + } > + > + data = elf_getdata(sec, NULL); > + if (!data) { > + fprintf(stderr, "Failed to data for __mcount_loc section.\n"); > + return -1; > + } > + > + addrs = malloc(data->d_size); > + if (!addrs) { > + fprintf(stderr, "Failed to allocate memory for ftrace addresses.\n"); > + return -1; > + } > + > + count = data->d_size / sizeof(unsigned long); not sure this is safe to do, e.g., if we are processing ELF of different bitness (32 vs 64). Maybev we can get the size of an entry from sh_entsize? > + memcpy(addrs, data->d_buf, data->d_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) > { > unsigned long *addrs = NULL, count, i; > int functions_valid = 0; > + bool kmod = false; > > /* > * Check if we are processing vmlinux image and > @@ -158,6 +218,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"); > @@ -174,9 +244,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. > + */ > + unsigned long 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..5ebbd2f9c84c 100644 > --- a/dutil.c > +++ b/dutil.c > @@ -196,6 +196,22 @@ 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) there is elf_getscn(), which does the same? > +{ > + Elf_Scn *sec = NULL; > + size_t cnt = 1; > + > + while ((sec = elf_nextscn(elf, sec)) != NULL) { > + if (cnt == idx) { > + gelf_getshdr(sec, shp); > + return sec; > + } > + ++cnt; > + } > + > + return NULL; > +} > + > 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 > ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 2/2] btf_encoder: Detect kernel module ftrace addresses 2020-11-27 4:18 ` Andrii Nakryiko @ 2020-11-27 17:40 ` Jiri Olsa 2020-11-27 20:39 ` Arnaldo Carvalho de Melo 0 siblings, 1 reply; 8+ messages in thread From: Jiri Olsa @ 2020-11-27 17:40 UTC (permalink / raw) To: Andrii Nakryiko Cc: Jiri Olsa, Arnaldo Carvalho de Melo, dwarves, bpf, Alexei Starovoitov, Andrii Nakryiko, Yonghong Song, Hao Luo On Thu, Nov 26, 2020 at 08:18:58PM -0800, Andrii Nakryiko wrote: > On Tue, Nov 24, 2020 at 8:22 AM Jiri Olsa <jolsa@kernel.org> wrote: > > > > Add support to detect kernel module dtrace addresses and use > > it as filter for functions. > > typo: dtrace -> ftrace? heh, honest typo I swear ;-) SNIP > > > > if (functions_cnt == functions_alloc) { > > functions_alloc = max(1000, functions_alloc * 3 / 2); > > @@ -84,8 +85,17 @@ static int collect_function(struct btf_elf *btfe, GElf_Sym *sym) > > functions = new; > > } > > > > + if (elf_sym__section(sym) != last_idx) { > > + int idx = elf_sym__section(sym); > > nit: elf_sym__section() called twice, maybe have sec_idx local variable instead? ugh, right, will fix > > > + > > + if (!elf_section_by_idx(btfe->elf, &sh, idx)) > > + return 0; > > isn't this an error and shouldn't return 0?.. I'm skiping functions without section, I did not want to fail all this because of some misplaced symbol mabe we could warn, but still go on.. > > > + 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; > > @@ -146,10 +156,60 @@ static int get_vmlinux_addrs(struct btf_elf *btfe, struct funcs_layout *fl, > > return 0; > > } > > > > +static int > > +get_kmod_addrs(struct btf_elf *btfe, unsigned long **paddrs, unsigned long *pcount) > > +{ > > + unsigned long *addrs, count; > > + GElf_Shdr shdr_mcount; > > + Elf_Data *data; > > + Elf_Scn *sec; > > + > > + /* 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); > > + } > > > nit: unnecessary {} for single-statement if ah ok, I put it because kernel guys scream with multiline conditions without {} > > > + return 0; > > + } > > + > > + data = elf_getdata(sec, NULL); > > + if (!data) { > > + fprintf(stderr, "Failed to data for __mcount_loc section.\n"); > > + return -1; > > + } > > + > > + addrs = malloc(data->d_size); > > + if (!addrs) { > > + fprintf(stderr, "Failed to allocate memory for ftrace addresses.\n"); > > + return -1; > > + } > > + > > + count = data->d_size / sizeof(unsigned long); > > not sure this is safe to do, e.g., if we are processing ELF of > different bitness (32 vs 64). Maybev we can get the size of an entry > from sh_entsize? it's not filled in, zero in my build we could get bitness from elf header and use that in here and also for vmlinux where it's hardcoded as well SNIP > > @@ -174,9 +244,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. > > + */ > > + unsigned long 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..5ebbd2f9c84c 100644 > > --- a/dutil.c > > +++ b/dutil.c > > @@ -196,6 +196,22 @@ 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) > > > there is elf_getscn(), which does the same? great, did not see it thanks, jirka ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 2/2] btf_encoder: Detect kernel module ftrace addresses 2020-11-27 17:40 ` Jiri Olsa @ 2020-11-27 20:39 ` Arnaldo Carvalho de Melo 0 siblings, 0 replies; 8+ messages in thread From: Arnaldo Carvalho de Melo @ 2020-11-27 20:39 UTC (permalink / raw) To: Jiri Olsa Cc: Andrii Nakryiko, Jiri Olsa, dwarves, bpf, Alexei Starovoitov, Andrii Nakryiko, Yonghong Song, Hao Luo Em Fri, Nov 27, 2020 at 06:40:37PM +0100, Jiri Olsa escreveu: > On Thu, Nov 26, 2020 at 08:18:58PM -0800, Andrii Nakryiko wrote: > > On Tue, Nov 24, 2020 at 8:22 AM Jiri Olsa <jolsa@kernel.org> wrote: > > > > > > Add support to detect kernel module dtrace addresses and use > > > it as filter for functions. > > > > typo: dtrace -> ftrace? > > heh, honest typo I swear ;-) f comes after d ;-) > SNIP > > > + /* 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); > > > + } > > nit: unnecessary {} for single-statement if > ah ok, I put it because kernel guys scream with multiline > conditions without {} You can keep it like that, or get free from 80 column constraints and make it: if (btf_elf__verbose) printf("%s: '%s' doesn't have __mcount_loc section\n", __func__, btfe->filename); - Arnaldo ^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2020-11-27 20:41 UTC | newest] Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2020-11-24 16:19 [RFC 0/2] btf_encoder: Detect kernel modules Jiri Olsa 2020-11-24 16:19 ` [PATCH 1/2] btf_encoder: Factor filter_functions function Jiri Olsa 2020-11-27 4:05 ` Andrii Nakryiko 2020-11-27 17:21 ` Jiri Olsa 2020-11-24 16:19 ` [PATCH 2/2] btf_encoder: Detect kernel module ftrace addresses Jiri Olsa 2020-11-27 4:18 ` Andrii Nakryiko 2020-11-27 17:40 ` Jiri Olsa 2020-11-27 20:39 ` Arnaldo Carvalho de Melo
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).