pahole: Introduce --prettify option
The use of isatty(0) to switch into pretty printing is problematic as reported by Bernd Buschinski, that ran into problems with his scripts: ======================================================================== I am using pahole 1.21 and I recently noticed that I no longer have any pahole output in several scripts. Using (on the command line): $ pahole -V -E -C my_struct /path/to/my/debug.o works fine and gives the expected output. But: $ parallel -j 1 pahole -V -E -C my_struct ::: /path/to/my/debug.o gives nothing, no stderr, no stdout and ret code 0. After testing some versions, it works fine in 1.17 and no longer works in 1.18. ======================================================================== Since the pretty printer broke existing scripts, and its a relatively new feature, lets switch to using a explicit command line option to activate the pretty printer, i.e. where we used: $ pahole --header elf64_hdr < /bin/bash We now use one of: ⬢[acme@toolbox pahole]$ pahole --header elf64_hdr --prettify=/bin/bash { .e_ident = { 127, 69, 76, 70, 2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, .e_type = 3, .e_machine = 62, .e_version = 1, .e_entry = 204016, .e_phoff = 64, .e_shoff = 1388096, .e_flags = 0, .e_ehsize = 64, .e_phentsize = 56, .e_phnum = 13, .e_shentsize = 64, .e_shnum = 31, .e_shstrndx = 30, }, ⬢[acme@toolbox pahole]$ pahole --header elf64_hdr --prettify /bin/bash { .e_ident = { 127, 69, 76, 70, 2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, .e_type = 3, .e_machine = 62, .e_version = 1, .e_entry = 204016, .e_phoff = 64, .e_shoff = 1388096, .e_flags = 0, .e_ehsize = 64, .e_phentsize = 56, .e_phnum = 13, .e_shentsize = 64, .e_shnum = 31, .e_shstrndx = 30, }, ⬢[acme@toolbox pahole]$ pahole --header elf64_hdr --prettify - < /bin/bash { .e_ident = { 127, 69, 76, 70, 2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, .e_type = 3, .e_machine = 62, .e_version = 1, .e_entry = 204016, .e_phoff = 64, .e_shoff = 1388096, .e_flags = 0, .e_ehsize = 64, .e_phentsize = 56, .e_phnum = 13, .e_shentsize = 64, .e_shnum = 31, .e_shstrndx = 30, }, ⬢[acme@toolbox pahole]$ pahole --header elf64_hdr --prettify=- < /bin/bash { .e_ident = { 127, 69, 76, 70, 2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, .e_type = 3, .e_machine = 62, .e_version = 1, .e_entry = 204016, .e_phoff = 64, .e_shoff = 1388096, .e_flags = 0, .e_ehsize = 64, .e_phentsize = 56, .e_phnum = 13, .e_shentsize = 64, .e_shnum = 31, .e_shstrndx = 30, }, ⬢[acme@toolbox pahole]$ Reported-by: Bernd Buschinski <b.buschinski@googlemail.com> Report-Link: https://lore.kernel.org/dwarves/CACN-hLVoz2tWrtgDLabOv6S1-H_8RD2fh8SV6EnADF1ikMxrmw@mail.gmail.com/ Tested-by-by: Bernd Buschinski <b.buschinski@googlemail.com> Test-Link: https://lore.kernel.org/dwarves/CACN-hLXgHWdBkyMz+w58qX8DaV+WJ1mj1qheGBHbPv4fqozi5w@mail.gmail.com/ Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
parent
bc36e94f32
commit
33e0d5f874
@ -21,7 +21,7 @@ It also uses these structure layouts to pretty print data feed to its standard
|
||||
input, e.g.:
|
||||
.PP
|
||||
.nf
|
||||
$ pahole --header elf64_hdr < /lib/modules/5.8.0-rc6+/build/vmlinux
|
||||
$ pahole --header elf64_hdr --prettify /lib/modules/5.8.0-rc6+/build/vmlinux
|
||||
{
|
||||
.e_ident = { 127, 69, 76, 70, 2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
|
||||
.e_type = 2,
|
||||
@ -566,8 +566,8 @@ $
|
||||
|
||||
.SH PRETTY PRINTING
|
||||
.P
|
||||
pahole can also use the data structure types to pretty print raw data coming
|
||||
from its standard input.
|
||||
pahole can also use the data structure types to pretty print raw data specified via --prettify.
|
||||
To consume raw data from the standard input, just use '--prettify -'
|
||||
.P
|
||||
It can also pretty print raw data from stdin according to the type specified:
|
||||
.PP
|
||||
@ -585,7 +585,7 @@ $
|
||||
$ ls -la versions
|
||||
-rw-rw-r--. 1 acme acme 7616 Jun 25 11:33 versions
|
||||
$
|
||||
$ pahole --count 3 -C modversion_info drivers/scsi/sg.ko < versions
|
||||
$ pahole --count 3 -C modversion_info drivers/scsi/sg.ko --prettify versions
|
||||
{
|
||||
.crc = 0x8dabd84,
|
||||
.name = "module_layout",
|
||||
@ -599,7 +599,7 @@ $ pahole --count 3 -C modversion_info drivers/scsi/sg.ko < versions
|
||||
.name = "param_ops_int",
|
||||
},
|
||||
$
|
||||
$ pahole --skip 1 --count 2 -C modversion_info drivers/scsi/sg.ko < versions
|
||||
$ pahole --skip 1 --count 2 -C modversion_info drivers/scsi/sg.ko --prettify - < versions
|
||||
{
|
||||
.crc = 0x45e4617b,
|
||||
.name = "no_llseek",
|
||||
@ -611,7 +611,7 @@ $ pahole --skip 1 --count 2 -C modversion_info drivers/scsi/sg.ko < versions
|
||||
$
|
||||
This is equivalent to:
|
||||
|
||||
$ pahole --seek_bytes 64 --count 1 -C modversion_info drivers/scsi/sg.ko < versions
|
||||
$ pahole --seek_bytes 64 --count 1 -C modversion_info drivers/scsi/sg.ko --prettify versions
|
||||
{
|
||||
.crc = 0x45e4617b,
|
||||
.name = "no_llseek",
|
||||
@ -662,7 +662,7 @@ $
|
||||
Now we can use this to show the first record from offset zero:
|
||||
.PP
|
||||
.nf
|
||||
$ pahole -C elf64_hdr --count 1 < /lib/modules/5.8.0-rc3+/build/vmlinux
|
||||
$ pahole -C elf64_hdr --count 1 --prettify /lib/modules/5.8.0-rc3+/build/vmlinux
|
||||
{
|
||||
.e_ident = { 127, 69, 76, 70, 2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
|
||||
.e_type = 2,
|
||||
@ -685,7 +685,7 @@ $
|
||||
This is equivalent to:
|
||||
.PP
|
||||
.nf
|
||||
$ pahole --header elf64_hdr < /lib/modules/5.8.0-rc3+/build/vmlinux
|
||||
$ pahole --header elf64_hdr --prettify /lib/modules/5.8.0-rc3+/build/vmlinux
|
||||
.fi
|
||||
.P
|
||||
The --header option also allows reference in other command line options to fields in the header.
|
||||
@ -693,7 +693,7 @@ This is useful when one wants to show multiple records in a file and the range w
|
||||
are located is specified in header fields, such as for perf.data files:
|
||||
.PP
|
||||
.nf
|
||||
$ pahole --hex ~/bin/perf --header perf_file_header < perf.data
|
||||
$ pahole --hex ~/bin/perf --header perf_file_header --prettify perf.data
|
||||
{
|
||||
.magic = 0x32454c4946524550,
|
||||
.size = 0x68,
|
||||
@ -718,7 +718,7 @@ $
|
||||
So to display the cgroups records in the perf_file_header.data section we can use:
|
||||
.PP
|
||||
.nf
|
||||
$ pahole ~/bin/perf --header=perf_file_header --seek_bytes '$header.data.offset' --size_bytes='$header.data.size' -C 'perf_event_header(sizeof,type,type_enum=perf_event_type,filter=type==PERF_RECORD_CGROUP)' < perf.data
|
||||
$ pahole ~/bin/perf --header=perf_file_header --seek_bytes '$header.data.offset' --size_bytes='$header.data.size' -C 'perf_event_header(sizeof,type,type_enum=perf_event_type,filter=type==PERF_RECORD_CGROUP)' --prettify perf.data
|
||||
{
|
||||
.header = {
|
||||
.type = PERF_RECORD_CGROUP,
|
||||
@ -770,7 +770,7 @@ $
|
||||
For the common case of the header having a member that has the 'offset' and 'size' members, it is possible to use this more compact form:
|
||||
.PP
|
||||
.nf
|
||||
$ pahole ~/bin/perf --header=perf_file_header --range=data -C 'perf_event_header(sizeof,type,type_enum=perf_event_type,filter=type==PERF_RECORD_CGROUP)' < perf.data
|
||||
$ pahole ~/bin/perf --header=perf_file_header --range=data -C 'perf_event_header(sizeof,type,type_enum=perf_event_type,filter=type==PERF_RECORD_CGROUP)' --prettify perf.data
|
||||
.fi
|
||||
.P
|
||||
This uses ~/bin/perf to get the type definitions, the defines 'struct perf_file_header' as the header,
|
||||
@ -844,7 +844,7 @@ If we remove that type_enum=perf_event_type, we will lose the conversion of 'str
|
||||
more descriptive 'struct perf_record_cgroup', and also the beautification of the header.type field:
|
||||
.PP
|
||||
.nf
|
||||
$ pahole ~/bin/perf --header=perf_file_header --seek_bytes '$header.data.offset' --size_bytes='$header.data.size' -C 'perf_event_header(sizeof,type,filter=type==19)' < perf.data
|
||||
$ pahole ~/bin/perf --header=perf_file_header --seek_bytes '$header.data.offset' --size_bytes='$header.data.size' -C 'perf_event_header(sizeof,type,filter=type==19)' --prettify perf.data
|
||||
{
|
||||
.type = 19,
|
||||
.misc = 0,
|
||||
@ -876,7 +876,7 @@ $
|
||||
Some of the records are not found in 'type_enum=perf_event_type' so some of the records don't get converted to a type that fully shows its contents. For perf we know that those are in another enumeration, 'enum perf_user_event_type', so, for these cases, we can create a 'virtual enum', i.e. the sum of two enums and then get all those entries decoded and properly casted, first few records with just 'enum perf_event_type':
|
||||
.PP
|
||||
.nf
|
||||
$ pahole ~/bin/perf --header=perf_file_header --seek_bytes '$header.data.offset' --size_bytes='$header.data.size' -C 'perf_event_header(sizeof,type,type_enum=perf_event_type)' --count 4 < perf.data
|
||||
$ pahole ~/bin/perf --header=perf_file_header --seek_bytes '$header.data.offset' --size_bytes='$header.data.size' -C 'perf_event_header(sizeof,type,type_enum=perf_event_type)' --count 4 --prettify perf.data
|
||||
{
|
||||
.type = 79,
|
||||
.misc = 0,
|
||||
@ -907,7 +907,7 @@ $
|
||||
Now with both enumerations, i.e. with 'type_enum=perf_event_type+perf_user_event_type':
|
||||
.PP
|
||||
.nf
|
||||
$ pahole ~/bin/perf --header=perf_file_header --seek_bytes '$header.data.offset' --size_bytes='$header.data.size' -C 'perf_event_header(sizeof,type,type_enum=perf_event_type+perf_user_event_type)' --count 5 < perf.data
|
||||
$ pahole ~/bin/perf --header=perf_file_header --seek_bytes '$header.data.offset' --size_bytes='$header.data.size' -C 'perf_event_header(sizeof,type,type_enum=perf_event_type+perf_user_event_type)' --count 5 --prettify perf.data
|
||||
{
|
||||
.header = {
|
||||
.type = PERF_RECORD_TIME_CONV,
|
||||
@ -966,7 +966,7 @@ data range with the following command:
|
||||
.PP
|
||||
.nf
|
||||
pahole ~/bin/perf --header=perf_file_header \
|
||||
-C 'perf_file_attr(range=attrs),perf_event_header(range=data,sizeof,type,type_enum=perf_event_type+perf_user_event_type)' < perf.data
|
||||
-C 'perf_file_attr(range=attrs),perf_event_header(range=data,sizeof,type,type_enum=perf_event_type+perf_user_event_type)' --prettify perf.data
|
||||
.fi
|
||||
|
||||
.SH SEE ALSO
|
||||
|
40
pahole.c
40
pahole.c
@ -35,6 +35,9 @@ static bool skip_encoding_btf_vars;
|
||||
static bool btf_encode_force;
|
||||
static const char *base_btf_file;
|
||||
|
||||
static const char *prettify_input_filename;
|
||||
static FILE *prettify_input;
|
||||
|
||||
static uint8_t class__include_anonymous;
|
||||
static uint8_t class__include_nested_anonymous;
|
||||
static uint8_t word_size, original_word_size;
|
||||
@ -854,6 +857,7 @@ ARGP_PROGRAM_VERSION_HOOK_DEF = dwarves_print_version;
|
||||
#define ARGP_with_flexible_array 324
|
||||
#define ARGP_kabi_prefix 325
|
||||
#define ARGP_btf_encode_detached 326
|
||||
#define ARGP_prettify_input_filename 327
|
||||
|
||||
static const struct argp_option pahole__options[] = {
|
||||
{
|
||||
@ -1202,6 +1206,12 @@ static const struct argp_option pahole__options[] = {
|
||||
.key = ARGP_numeric_version,
|
||||
.doc = "Print a numeric version, i.e. 119 instead of v1.19"
|
||||
},
|
||||
{
|
||||
.name = "prettify",
|
||||
.key = ARGP_prettify_input_filename,
|
||||
.arg = "PATH",
|
||||
.doc = "Path to the raw data to pretty print",
|
||||
},
|
||||
{
|
||||
.name = NULL,
|
||||
}
|
||||
@ -1332,6 +1342,8 @@ static error_t pahole__options_parser(int key, char *arg,
|
||||
btf_gen_floats = true; break;
|
||||
case ARGP_with_flexible_array:
|
||||
show_with_flexible_array = true; break;
|
||||
case ARGP_prettify_input_filename:
|
||||
prettify_input_filename = arg; break;
|
||||
default:
|
||||
return ARGP_ERR_UNKNOWN;
|
||||
}
|
||||
@ -2586,7 +2598,7 @@ static enum load_steal_kind pahole_stealer(struct cu *cu,
|
||||
class_id = 0;
|
||||
}
|
||||
|
||||
if (!isatty(0)) {
|
||||
if (prettify_input) {
|
||||
prototype->class = class;
|
||||
prototype->cu = cu;
|
||||
continue;
|
||||
@ -2624,7 +2636,7 @@ static enum load_steal_kind pahole_stealer(struct cu *cu,
|
||||
|
||||
// If we got here with pretty printing is because we have everything solved except for type_enum or --header
|
||||
|
||||
if (!isatty(0)) {
|
||||
if (prettify_input) {
|
||||
// Check if we need to continue loading CUs to get those type_enum= and --header resolved
|
||||
if (header == NULL && conf.header_type)
|
||||
return LSK__KEEPIT;
|
||||
@ -2637,7 +2649,7 @@ static enum load_steal_kind pahole_stealer(struct cu *cu,
|
||||
// All set, pretty print it!
|
||||
list_for_each_entry_safe(prototype, n, &class_names, node) {
|
||||
list_del_init(&prototype->node);
|
||||
if (prototype__stdio_fprintf_value(prototype, header, stdin, stdout) < 0)
|
||||
if (prototype__stdio_fprintf_value(prototype, header, prettify_input, stdout) < 0)
|
||||
break;
|
||||
}
|
||||
|
||||
@ -2783,9 +2795,6 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
int err, remaining, rc = EXIT_FAILURE;
|
||||
|
||||
if (!isatty(0))
|
||||
conf.hex_fmt = 0;
|
||||
|
||||
if (argp_parse(&pahole__argp, argc, argv, 0, &remaining, NULL)) {
|
||||
argp_help(&pahole__argp, stderr, ARGP_HELP_SEE, argv[0]);
|
||||
goto out;
|
||||
@ -2801,6 +2810,19 @@ int main(int argc, char *argv[])
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (prettify_input_filename) {
|
||||
if (strcmp(prettify_input_filename, "-") == 0) {
|
||||
prettify_input = stdin;
|
||||
} else {
|
||||
prettify_input = fopen(prettify_input_filename, "r");
|
||||
if (prettify_input == NULL) {
|
||||
fprintf(stderr, "Failed to read input '%s': %s\n",
|
||||
prettify_input_filename, strerror(errno));
|
||||
goto out_dwarves_exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (base_btf_file) {
|
||||
conf_load.base_btf = btf__parse(base_btf_file, NULL);
|
||||
if (libbpf_get_error(conf_load.base_btf)) {
|
||||
@ -2825,7 +2847,7 @@ int main(int argc, char *argv[])
|
||||
conf_load.steal = pahole_stealer;
|
||||
|
||||
// Make 'pahole --header type < file' a shorter form of 'pahole -C type --count 1 < file'
|
||||
if (conf.header_type && !class_name && !isatty(0)) {
|
||||
if (conf.header_type && !class_name && prettify_input) {
|
||||
conf.count = 1;
|
||||
class_name = conf.header_type;
|
||||
conf.header_type = 0; // so that we don't read it and then try to read the -C type
|
||||
@ -2923,6 +2945,10 @@ out_cus_delete:
|
||||
conf_load.base_btf = NULL;
|
||||
#endif
|
||||
out_dwarves_exit:
|
||||
if (prettify_input && prettify_input != stdin) {
|
||||
fclose(prettify_input);
|
||||
prettify_input = NULL;
|
||||
}
|
||||
#ifdef DEBUG_CHECK_LEAKS
|
||||
dwarves__exit();
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user