Now we just pass a NULL terminated array of filenames, since we got rid
of that ugly -e insertion hack.
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This is still ugly, as the processing of argp was done on the loader so
that we can use the libdwfl argp processing, doing the tool argp
processing as a child. But then when we find out that there is no DWARF
info we fall back to another debugging format, with CTF being the only
other one supported as of now.
I used this scheme as when developing the CTF decoder and using pahole
on a binary with both CTF and DWARF info I would like to get the CTF
processed first.
So we still need some good refactoring here to get this sorted out in a
way that the user can specify the order of decoding, and perhaps even
ask for decoding _both_ and comparing if the results are the same, i.e.
if the (potentially subset of) information decoded from the first (that
may have less information: CTF) is the same as decoded from the second
(DWARF, more verbose).
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
And make the dwarves use it, so that we can remove duplicate strings in
a multi-CU file (vmlinux anyone?) and have it ready for insertion in a
compressed DWARF format with just the types, or better, CTF or some new
compressed debugging info format.
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Basically a wrapper for ftype__fprintf(&function__proto, ...) for the
cases we want the prototype rendered to a buffer, not to a file.
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Thanks to Dennis Lubert for bringing this to my attention, now tons of BRAIN
FART ALERTs are gone.
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
By inlining them in the output when possible, that way we get context on where
the problem is, etc.
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
For correctly created and completely parsed debugging information the type will
always be found, but as we still need to parse more tags and expecting
debugging information to be always correctly built is not sane... sprinkle some
asserts.
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This is trying to get CTF friendly, where bitfields are not stored in the
equivalent to the DW_TAG_member dwarf TAG, but on "base types" with bit sizes
different than the real in the DWARF sense, base types (char, long, etc).
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
In libdwarves.so well continue using DW_TAG_ entries and types for now, but its
becoming non-DWARF specific as will be demonstrated with the introduction of
ctf_loader.c in the upcoming csets.
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
memdup() is only referenced from dwarves.c. This patch defines them
static. Further symbol hiding can be accomplished via GCC attributes:
Signed-off-by: Hagen Paul Pfeifer <hagen@jauu.net>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Almost halves the time spent on processing a x86_64 vmlinux. Good, we
have features, now lets have performance ;-)
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
It will return NULL, this will be useful for codiff to use /dev/null as one of
the files being compared. And if you look for something in NULL, you better
get NULL, seems like a useful convention, huh?
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
What a mouthful ;-) To be used in finding the most aligned member in a non-packed
type, i.e. one that originally wasn't __attribute__((packed)).
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
That is not present in stable distros, where people trying the dwarves, for
now, should just disable build id support in this awkward way till I find out
how to do it properly using cmake.
Or you can get so annoyed to the point of submitting a patch to fix this ;-)
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This was found on an old openbsd kernel image that Leonardo Chiquito built
enabling DWARF instead of the default, STABS debugging format 8)
Just this struct has this characteristic:
struct ricoh_is410_window_data {
struct scsi_window_data window_data; /* 0 48 */
u_int8_t res1; /* 48 1 */
u_int8_t res2; /* 49 1 */
/* Bitfield combined with previous fields */
u_int mrif:1; /* 48:15 4 */
u_int filtering:3; /* 48:12 4 */
u_int gamma_id:4; /* 48: 8 4 */
/* size: 52, cachelines: 1 */
/* bit_padding: 24 bits */
/* last cacheline: 52 bytes */
};
Now there are no BRAIN FART ALERT!s when paholing openbsd, yay!
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Lots of BRAIN FART ALERT!s removed!
There is still a problem in class__find_holes where we don't catch bitfields
that are combined with previous fields where the byte offset for the bitfield
is the same as the previous field. This happens when the compiler combines a
bitfield with real byte size > 1 just after a one or two bytes field that is at
an alignment boundary.
Will fix later.
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Make class__find_holes understand that when a byte offset goes backward it is
because the compiler is "combining" small bitfields with previous fields, and
using from the end of the combined bitfield + small fields. This made your
head hurt, huh? One example:
struct usb_bus {
struct device * controller; /* 0 8 */
int busnum; /* 8 4 */
/* XXX 4 bytes hole, try to pack */
char * bus_name; /* 16 8 */
u8 uses_dma; /* 24 1 */
u8 otg_port; /* 25 1 */
/* Bitfield combined with previous fields */
unsigned int is_b_host:1; /* 24:15 4 */
unsigned int b_hnp_enable:1; /* 24:14 4 */
/* XXX 14 bits hole, try to pack */
int devnum_next; /* 28 4 */
struct usb_devmap devmap; /* 32 16 */
<SNIP>
};
See? is_b_host:1 .. b_hnp_enable:1 makes a bitfield of just two bits.
The programmer decided to make this a 'unsigned int' bitfield, so taking 4 bytes.
And placed this "4" bytes bitfield just after two fields of one byte.
The compiler put the "4" bytes bitfield "in the same place" as the "uses_dma"
field, but its really not clobbering it neither "otg_port", as it allocates it
from (offset 24 + sizeof(unsigned int) - 1), backwards.
So at the end there is a, now correctly calculated, 14 bits hole, and that
matches the bit offset used for the last field, that is "14", as offsets for
bits and bytes starts at zero, all is explained now.
One last thing is that since we actually have 14 bits we in fact have a one
byte hole + a 6 bits hole, but that should be clear (haha) for those looking
for holes :-)
Nah, just run pahole reorganize on this beast and you'll have (for the complete
structure, with the <SNIP> part back in:
struct usb_bus {
struct device * controller; /* 0 8 */
int busnum; /* 8 4 */
unsigned char is_b_host:1; /* 12:247 1 */
unsigned char b_hnp_enable:1; /* 12:246 1 */
/* XXX 6 bits hole, try to pack */
u8 otg_port; /* 13 1 */
u8 uses_dma; /* 14 1 */
/* XXX 1 byte hole, try to pack */
char * bus_name; /* 16 8 */
int bandwidth_isoc_reqs; /* 24 4 */
int devnum_next; /* 28 4 */
struct usb_devmap devmap; /* 32 16 */
struct usb_device * root_hub; /* 48 8 */
struct list_head bus_list; /* 56 16 */
/* --- cacheline 1 boundary (64 bytes) was 8 bytes ago --- */
int bandwidth_allocated; /* 72 4 */
int bandwidth_int_reqs; /* 76 4 */
struct dentry * usbfs_dentry; /* 80 8 */
struct class_device * class_dev; /* 88 8 */
struct mon_bus * mon_bus; /* 96 8 */
int monitored; /* 104 4 */
/* size: 112, cachelines: 2 */
/* sum members: 107, holes: 1, sum holes: 1 */
/* bit holes: 1, sum bit holes: 6 bits */
/* padding: 4 */
/* last cacheline: 48 bytes */
}; /* saved 8 bytes! */
And we save 8 bytes and reduce the previous complexity. Hey, but look at those
bit offsets at is_b_host and b_hnp_enable... damn, exposing the bit offsets I
just exposed another bug, that is: the reorganization code is not fixing up the
bit offsets, one more for the TODO list, nah, just compile it and pass the
results back to the dwarves and we get:
struct usb_bus {
struct device * controller; /* 0 8 */
int busnum; /* 8 4 */
unsigned char is_b_host:1; /* 12: 7 1 */
unsigned char b_hnp_enable:1; /* 12: 6 1 */
/* XXX 6 bits hole, try to pack */
u8 otg_port; /* 13 1 */
u8 uses_dma; /* 14 1 */
/* XXX 1 byte hole, try to pack */
char * bus_name; /* 16 8 */
int bandwidth_isoc_reqs; /* 24 4 */
int devnum_next; /* 28 4 */
struct usb_devmap devmap; /* 32 16 */
struct usb_device * root_hub; /* 48 8 */
struct list_head bus_list; /* 56 16 */
/* --- cacheline 1 boundary (64 bytes) was 8 bytes ago --- */
int bandwidth_allocated; /* 72 4 */
int bandwidth_int_reqs; /* 76 4 */
struct dentry * usbfs_dentry; /* 80 8 */
struct class_device * class_dev; /* 88 8 */
struct mon_bus * mon_bus; /* 96 8 */
int monitored; /* 104 4 */
/* size: 112, cachelines: 2 */
/* sum members: 107, holes: 1, sum holes: 1 */
/* bit holes: 1, sum bit holes: 6 bits */
/* padding: 4 */
/* last cacheline: 48 bytes */
};
See? this time gcc fixed up things for us and even agreed on the reorganization
the dwarves did! 8-)
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Helps understanding how bitfields really work, and after all it is just
confusing, not wrong.
See this one:
struct usb_bus {
struct device * controller; /* 0 8 */
int busnum; /* 8 4 */
/* XXX 4 bytes hole, try to pack */
char * bus_name; /* 16 8 */
u8 uses_dma; /* 24 1 */
u8 otg_port; /* 25 1 */
/* WARNING: DWARF offset=24, real offset=26 */
unsigned int is_b_host:1; /* 24:15 4 */
unsigned int b_hnp_enable:1; /* 24:14 4 */
/* XXX 30 bits hole, try to pack */
int devnum_next; /* 28 4 */
<SNIP>
};
So the bitfield _really_ is at offset 24 and the "WARNING:" above is just
pahole not understanding how it works, i.e. it starts at 24 and since the
bitfield has a 'unsigned int' as its base type it goes from 24 to 27, the
offsets start at the end, i.e. from byte 27 back to byte 27, but as only two
bits are used, it puts bit padding at the end, at bit offset 0, that is the
last bit in byte 27 and uses the first bits of byte 26 at bit offset 14 and 15.
Now to make libdwarves finally understand this convention.
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This struct, from the linux kernel:
struct usb_bus {
struct device * controller; /* 0 8 */
int busnum; /* 8 4 */
char * bus_name; /* 16 8 */
u8 uses_dma; /* 24 1 */
u8 otg_port; /* 25 1 */
unsigned int is_b_host:1; /* 24 4 */
unsigned int b_hnp_enable:1; /* 24 4 */
int devnum_next; /* 28 4 */
struct usb_devmap devmap; /* 32 16 */
struct usb_device * root_hub; /* 48 8 */
struct list_head bus_list; /* 56 16 */
int bandwidth_allocated; /* 72 4 */
int bandwidth_int_reqs; /* 76 4 */
int bandwidth_isoc_reqs; /* 80 4 */
struct dentry * usbfs_dentry; /* 88 8 */
struct class_device * class_dev; /* 96 8 */
struct mon_bus * mon_bus; /* 104 8 */
int monitored; /* 112 4 */
};
Generates seemingly wrong DWARF when compiled with GCC:
struct usb_bus {
struct device * controller; /* 0 8 */
int busnum; /* 8 4 */
/* XXX 4 bytes hole, try to pack */
char * bus_name; /* 16 8 */
u8 uses_dma; /* 24 1 */
u8 otg_port; /* 25 1 */
/* WARNING: DWARF offset=24, real offset=26 */
unsigned int is_b_host:1; /* 24 4 */
unsigned int b_hnp_enable:1; /* 24 4 */
/* XXX 30 bits hole, try to pack */
int devnum_next; /* 28 4 */
struct usb_devmap devmap; /* 32 16 */
struct usb_device * root_hub; /* 48 8 */
struct list_head bus_list; /* 56 16 */
/* --- cacheline 1 boundary (64 bytes) was 10 bytes ago --- */
int bandwidth_allocated; /* 72 4 */
int bandwidth_int_reqs; /* 76 4 */
int bandwidth_isoc_reqs; /* 80 4 */
/* XXX 4 bytes hole, try to pack */
struct dentry * usbfs_dentry; /* 88 8 */
struct class_device * class_dev; /* 96 8 */
struct mon_bus * mon_bus; /* 104 8 */
int monitored; /* 112 4 */
/* size: 120, cachelines: 2 */
/* sum members: 110, holes: 2, sum holes: 8 */
/* bit holes: 1, sum bit holes: 30 bits */
/* padding: 4 */
/* last cacheline: 56 bytes */
/* BRAIN FART ALERT! 120 != 110 + 8(holes), diff = 2 */
};
Look at the offset for the first entry in the bitfield (is_b_host), the
compiler said in the DWARF info that it was at offset 25, when in fact it is at
offset 26 as can be seen when looking at the generated assembly code.
This previously was confusing libdwarves, as it uses subtracts the last offset
from the current offset to see what was the size the compiler really allocated
to then check if it is equal to the size of the previous entry, so as to detect
alignment holes.
The offsets are uint32_t, so cast both to int64_t when doing the calculation,
the existing code already deals with negative numbers that result in this
patologic case.
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
In ctracer we can find a function that receives as one of its arguments a
pointer to the target class and also a pointer to an alias or pointer class,
so we have to check if the function was already added to one of these lists:
class methods list
class aliases list
class pointer list
To avoid corrupting one of them by trying to add the function to multiple
lists.
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
When we are looking for members of some type in all CUs it may be that in
some CU we don't have the full type, but just a declaration.
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>