Message ID | 20240614172631.56803-14-atrajeev@linux.vnet.ibm.com (mailing list archive) |
---|---|
State | Handled Elsewhere, archived |
Headers | show |
Series | Add data type profiling support for powerpc | expand |
On Fri, Jun 14, 2024 at 10:56:28PM +0530, Athira Rajeev wrote: > Now perf uses the capstone library to disassemble the instructions in > x86. capstone is used (if available) for perf annotate to speed up. > Currently it only supports x86 architecture. Patch includes changes to > enable this in powerpc. For now, only for data type sort keys, this > method is used and only binary code (raw instruction) is read. This is > because powerpc approach to understand instructions and reg fields uses > raw instruction. The "cs_disasm" is currently not enabled. While > attempting to do cs_disasm, observation is that some of the instructions > were not identified (ex: extswsli, maddld) and it had to fallback to use > objdump. Hence enabling "cs_disasm" is added in comment section as a > TODO for powerpc. Well.. I'm not sure if I understand it correctly but it seems this function effectively does nothing more than the raw disassemble. Can we simply drop this patch for now? Or did I miss something? Thanks, Namhyung > > Signed-off-by: Athira Rajeev <atrajeev@linux.vnet.ibm.com> > --- > tools/perf/util/disasm.c | 143 +++++++++++++++++++++++++++++++++++++++ > 1 file changed, 143 insertions(+) > > diff --git a/tools/perf/util/disasm.c b/tools/perf/util/disasm.c > index 43743ca4bdc9..987bff9f71c3 100644 > --- a/tools/perf/util/disasm.c > +++ b/tools/perf/util/disasm.c > @@ -1592,6 +1592,144 @@ static void print_capstone_detail(cs_insn *insn, char *buf, size_t len, > } > } > > +static int symbol__disassemble_capstone_powerpc(char *filename, struct symbol *sym, > + struct annotate_args *args) > +{ > + struct annotation *notes = symbol__annotation(sym); > + struct map *map = args->ms.map; > + struct dso *dso = map__dso(map); > + struct nscookie nsc; > + u64 start = map__rip_2objdump(map, sym->start); > + u64 end = map__rip_2objdump(map, sym->end); > + u64 len = end - start; > + u64 offset; > + int i, fd, count; > + bool is_64bit = false; > + bool needs_cs_close = false; > + u8 *buf = NULL; > + struct find_file_offset_data data = { > + .ip = start, > + }; > + csh handle; > + char disasm_buf[512]; > + struct disasm_line *dl; > + u32 *line; > + bool disassembler_style = false; > + > + if (args->options->objdump_path) > + return -1; > + > + nsinfo__mountns_enter(dso->nsinfo, &nsc); > + fd = open(filename, O_RDONLY); > + nsinfo__mountns_exit(&nsc); > + if (fd < 0) > + return -1; > + > + if (file__read_maps(fd, /*exe=*/true, find_file_offset, &data, > + &is_64bit) == 0) > + goto err; > + > + if (!args->options->disassembler_style || > + !strcmp(args->options->disassembler_style, "att")) > + disassembler_style = true; > + > + if (capstone_init(maps__machine(args->ms.maps), &handle, is_64bit, disassembler_style) < 0) > + goto err; > + > + needs_cs_close = true; > + > + buf = malloc(len); > + if (buf == NULL) > + goto err; > + > + count = pread(fd, buf, len, data.offset); > + close(fd); > + fd = -1; > + > + if ((u64)count != len) > + goto err; > + > + line = (u32 *)buf; > + > + /* add the function address and name */ > + scnprintf(disasm_buf, sizeof(disasm_buf), "%#"PRIx64" <%s>:", > + start, sym->name); > + > + args->offset = -1; > + args->line = disasm_buf; > + args->line_nr = 0; > + args->fileloc = NULL; > + args->ms.sym = sym; > + > + dl = disasm_line__new(args); > + if (dl == NULL) > + goto err; > + > + annotation_line__add(&dl->al, ¬es->src->source); > + > + /* > + * TODO: enable disassm for powerpc > + * count = cs_disasm(handle, buf, len, start, len, &insn); > + * > + * For now, only binary code is saved in disassembled line > + * to be used in "type" and "typeoff" sort keys. Each raw code > + * is 32 bit instruction. So use "len/4" to get the number of > + * entries. > + */ > + count = len/4; > + > + for (i = 0, offset = 0; i < count; i++) { > + args->offset = offset; > + sprintf(args->line, "%x", line[i]); > + > + dl = disasm_line__new(args); > + if (dl == NULL) > + goto err; > + > + annotation_line__add(&dl->al, ¬es->src->source); > + > + offset += 4; > + } > + > + /* It failed in the middle */ > + if (offset != len) { > + struct list_head *list = ¬es->src->source; > + > + /* Discard all lines and fallback to objdump */ > + while (!list_empty(list)) { > + dl = list_first_entry(list, struct disasm_line, al.node); > + > + list_del_init(&dl->al.node); > + disasm_line__free(dl); > + } > + count = -1; > + } > + > +out: > + if (needs_cs_close) > + cs_close(&handle); > + free(buf); > + return count < 0 ? count : 0; > + > +err: > + if (fd >= 0) > + close(fd); > + if (needs_cs_close) { > + struct disasm_line *tmp; > + > + /* > + * It probably failed in the middle of the above loop. > + * Release any resources it might add. > + */ > + list_for_each_entry_safe(dl, tmp, ¬es->src->source, al.node) { > + list_del(&dl->al.node); > + free(dl); > + } > + } > + count = -1; > + goto out; > +} > + > static int symbol__disassemble_capstone(char *filename, struct symbol *sym, > struct annotate_args *args) > { > @@ -1949,6 +2087,11 @@ int symbol__disassemble(struct symbol *sym, struct annotate_args *args) > err = symbol__disassemble_dso(symfs_filename, sym, args); > if (err == 0) > goto out_remove_tmp; > +#ifdef HAVE_LIBCAPSTONE_SUPPORT > + err = symbol__disassemble_capstone_powerpc(symfs_filename, sym, args); > + if (err == 0) > + goto out_remove_tmp; > +#endif > } > } > > -- > 2.43.0 >
> On 25 Jun 2024, at 11:38 AM, Namhyung Kim <namhyung@kernel.org> wrote: > > On Fri, Jun 14, 2024 at 10:56:28PM +0530, Athira Rajeev wrote: >> Now perf uses the capstone library to disassemble the instructions in >> x86. capstone is used (if available) for perf annotate to speed up. >> Currently it only supports x86 architecture. Patch includes changes to >> enable this in powerpc. For now, only for data type sort keys, this >> method is used and only binary code (raw instruction) is read. This is >> because powerpc approach to understand instructions and reg fields uses >> raw instruction. The "cs_disasm" is currently not enabled. While >> attempting to do cs_disasm, observation is that some of the instructions >> were not identified (ex: extswsli, maddld) and it had to fallback to use >> objdump. Hence enabling "cs_disasm" is added in comment section as a >> TODO for powerpc. > > Well.. I'm not sure if I understand it correctly but it seems this > function effectively does nothing more than the raw disassemble. > Can we simply drop this patch for now? Or did I miss something? > > Thanks, > Namhyung Hi Namhyung Responded to this in previous patch ( for Patch number 3 ) Thanks Athira > >> >> Signed-off-by: Athira Rajeev <atrajeev@linux.vnet.ibm.com> >> --- >> tools/perf/util/disasm.c | 143 +++++++++++++++++++++++++++++++++++++++ >> 1 file changed, 143 insertions(+) >> >> diff --git a/tools/perf/util/disasm.c b/tools/perf/util/disasm.c >> index 43743ca4bdc9..987bff9f71c3 100644 >> --- a/tools/perf/util/disasm.c >> +++ b/tools/perf/util/disasm.c >> @@ -1592,6 +1592,144 @@ static void print_capstone_detail(cs_insn *insn, char *buf, size_t len, >> } >> } >> >> +static int symbol__disassemble_capstone_powerpc(char *filename, struct symbol *sym, >> + struct annotate_args *args) >> +{ >> + struct annotation *notes = symbol__annotation(sym); >> + struct map *map = args->ms.map; >> + struct dso *dso = map__dso(map); >> + struct nscookie nsc; >> + u64 start = map__rip_2objdump(map, sym->start); >> + u64 end = map__rip_2objdump(map, sym->end); >> + u64 len = end - start; >> + u64 offset; >> + int i, fd, count; >> + bool is_64bit = false; >> + bool needs_cs_close = false; >> + u8 *buf = NULL; >> + struct find_file_offset_data data = { >> + .ip = start, >> + }; >> + csh handle; >> + char disasm_buf[512]; >> + struct disasm_line *dl; >> + u32 *line; >> + bool disassembler_style = false; >> + >> + if (args->options->objdump_path) >> + return -1; >> + >> + nsinfo__mountns_enter(dso->nsinfo, &nsc); >> + fd = open(filename, O_RDONLY); >> + nsinfo__mountns_exit(&nsc); >> + if (fd < 0) >> + return -1; >> + >> + if (file__read_maps(fd, /*exe=*/true, find_file_offset, &data, >> + &is_64bit) == 0) >> + goto err; >> + >> + if (!args->options->disassembler_style || >> + !strcmp(args->options->disassembler_style, "att")) >> + disassembler_style = true; >> + >> + if (capstone_init(maps__machine(args->ms.maps), &handle, is_64bit, disassembler_style) < 0) >> + goto err; >> + >> + needs_cs_close = true; >> + >> + buf = malloc(len); >> + if (buf == NULL) >> + goto err; >> + >> + count = pread(fd, buf, len, data.offset); >> + close(fd); >> + fd = -1; >> + >> + if ((u64)count != len) >> + goto err; >> + >> + line = (u32 *)buf; >> + >> + /* add the function address and name */ >> + scnprintf(disasm_buf, sizeof(disasm_buf), "%#"PRIx64" <%s>:", >> + start, sym->name); >> + >> + args->offset = -1; >> + args->line = disasm_buf; >> + args->line_nr = 0; >> + args->fileloc = NULL; >> + args->ms.sym = sym; >> + >> + dl = disasm_line__new(args); >> + if (dl == NULL) >> + goto err; >> + >> + annotation_line__add(&dl->al, ¬es->src->source); >> + >> + /* >> + * TODO: enable disassm for powerpc >> + * count = cs_disasm(handle, buf, len, start, len, &insn); >> + * >> + * For now, only binary code is saved in disassembled line >> + * to be used in "type" and "typeoff" sort keys. Each raw code >> + * is 32 bit instruction. So use "len/4" to get the number of >> + * entries. >> + */ >> + count = len/4; >> + >> + for (i = 0, offset = 0; i < count; i++) { >> + args->offset = offset; >> + sprintf(args->line, "%x", line[i]); >> + >> + dl = disasm_line__new(args); >> + if (dl == NULL) >> + goto err; >> + >> + annotation_line__add(&dl->al, ¬es->src->source); >> + >> + offset += 4; >> + } >> + >> + /* It failed in the middle */ >> + if (offset != len) { >> + struct list_head *list = ¬es->src->source; >> + >> + /* Discard all lines and fallback to objdump */ >> + while (!list_empty(list)) { >> + dl = list_first_entry(list, struct disasm_line, al.node); >> + >> + list_del_init(&dl->al.node); >> + disasm_line__free(dl); >> + } >> + count = -1; >> + } >> + >> +out: >> + if (needs_cs_close) >> + cs_close(&handle); >> + free(buf); >> + return count < 0 ? count : 0; >> + >> +err: >> + if (fd >= 0) >> + close(fd); >> + if (needs_cs_close) { >> + struct disasm_line *tmp; >> + >> + /* >> + * It probably failed in the middle of the above loop. >> + * Release any resources it might add. >> + */ >> + list_for_each_entry_safe(dl, tmp, ¬es->src->source, al.node) { >> + list_del(&dl->al.node); >> + free(dl); >> + } >> + } >> + count = -1; >> + goto out; >> +} >> + >> static int symbol__disassemble_capstone(char *filename, struct symbol *sym, >> struct annotate_args *args) >> { >> @@ -1949,6 +2087,11 @@ int symbol__disassemble(struct symbol *sym, struct annotate_args *args) >> err = symbol__disassemble_dso(symfs_filename, sym, args); >> if (err == 0) >> goto out_remove_tmp; >> +#ifdef HAVE_LIBCAPSTONE_SUPPORT >> + err = symbol__disassemble_capstone_powerpc(symfs_filename, sym, args); >> + if (err == 0) >> + goto out_remove_tmp; >> +#endif >> } >> } >> >> -- >> 2.43.0 >> >
diff --git a/tools/perf/util/disasm.c b/tools/perf/util/disasm.c index 43743ca4bdc9..987bff9f71c3 100644 --- a/tools/perf/util/disasm.c +++ b/tools/perf/util/disasm.c @@ -1592,6 +1592,144 @@ static void print_capstone_detail(cs_insn *insn, char *buf, size_t len, } } +static int symbol__disassemble_capstone_powerpc(char *filename, struct symbol *sym, + struct annotate_args *args) +{ + struct annotation *notes = symbol__annotation(sym); + struct map *map = args->ms.map; + struct dso *dso = map__dso(map); + struct nscookie nsc; + u64 start = map__rip_2objdump(map, sym->start); + u64 end = map__rip_2objdump(map, sym->end); + u64 len = end - start; + u64 offset; + int i, fd, count; + bool is_64bit = false; + bool needs_cs_close = false; + u8 *buf = NULL; + struct find_file_offset_data data = { + .ip = start, + }; + csh handle; + char disasm_buf[512]; + struct disasm_line *dl; + u32 *line; + bool disassembler_style = false; + + if (args->options->objdump_path) + return -1; + + nsinfo__mountns_enter(dso->nsinfo, &nsc); + fd = open(filename, O_RDONLY); + nsinfo__mountns_exit(&nsc); + if (fd < 0) + return -1; + + if (file__read_maps(fd, /*exe=*/true, find_file_offset, &data, + &is_64bit) == 0) + goto err; + + if (!args->options->disassembler_style || + !strcmp(args->options->disassembler_style, "att")) + disassembler_style = true; + + if (capstone_init(maps__machine(args->ms.maps), &handle, is_64bit, disassembler_style) < 0) + goto err; + + needs_cs_close = true; + + buf = malloc(len); + if (buf == NULL) + goto err; + + count = pread(fd, buf, len, data.offset); + close(fd); + fd = -1; + + if ((u64)count != len) + goto err; + + line = (u32 *)buf; + + /* add the function address and name */ + scnprintf(disasm_buf, sizeof(disasm_buf), "%#"PRIx64" <%s>:", + start, sym->name); + + args->offset = -1; + args->line = disasm_buf; + args->line_nr = 0; + args->fileloc = NULL; + args->ms.sym = sym; + + dl = disasm_line__new(args); + if (dl == NULL) + goto err; + + annotation_line__add(&dl->al, ¬es->src->source); + + /* + * TODO: enable disassm for powerpc + * count = cs_disasm(handle, buf, len, start, len, &insn); + * + * For now, only binary code is saved in disassembled line + * to be used in "type" and "typeoff" sort keys. Each raw code + * is 32 bit instruction. So use "len/4" to get the number of + * entries. + */ + count = len/4; + + for (i = 0, offset = 0; i < count; i++) { + args->offset = offset; + sprintf(args->line, "%x", line[i]); + + dl = disasm_line__new(args); + if (dl == NULL) + goto err; + + annotation_line__add(&dl->al, ¬es->src->source); + + offset += 4; + } + + /* It failed in the middle */ + if (offset != len) { + struct list_head *list = ¬es->src->source; + + /* Discard all lines and fallback to objdump */ + while (!list_empty(list)) { + dl = list_first_entry(list, struct disasm_line, al.node); + + list_del_init(&dl->al.node); + disasm_line__free(dl); + } + count = -1; + } + +out: + if (needs_cs_close) + cs_close(&handle); + free(buf); + return count < 0 ? count : 0; + +err: + if (fd >= 0) + close(fd); + if (needs_cs_close) { + struct disasm_line *tmp; + + /* + * It probably failed in the middle of the above loop. + * Release any resources it might add. + */ + list_for_each_entry_safe(dl, tmp, ¬es->src->source, al.node) { + list_del(&dl->al.node); + free(dl); + } + } + count = -1; + goto out; +} + static int symbol__disassemble_capstone(char *filename, struct symbol *sym, struct annotate_args *args) { @@ -1949,6 +2087,11 @@ int symbol__disassemble(struct symbol *sym, struct annotate_args *args) err = symbol__disassemble_dso(symfs_filename, sym, args); if (err == 0) goto out_remove_tmp; +#ifdef HAVE_LIBCAPSTONE_SUPPORT + err = symbol__disassemble_capstone_powerpc(symfs_filename, sym, args); + if (err == 0) + goto out_remove_tmp; +#endif } }
Now perf uses the capstone library to disassemble the instructions in x86. capstone is used (if available) for perf annotate to speed up. Currently it only supports x86 architecture. Patch includes changes to enable this in powerpc. For now, only for data type sort keys, this method is used and only binary code (raw instruction) is read. This is because powerpc approach to understand instructions and reg fields uses raw instruction. The "cs_disasm" is currently not enabled. While attempting to do cs_disasm, observation is that some of the instructions were not identified (ex: extswsli, maddld) and it had to fallback to use objdump. Hence enabling "cs_disasm" is added in comment section as a TODO for powerpc. Signed-off-by: Athira Rajeev <atrajeev@linux.vnet.ibm.com> --- tools/perf/util/disasm.c | 143 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 143 insertions(+)