[DWARVES]: Add sanity check when calculating size from DWARF offsets
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>
This commit is contained in:
parent
be79835bf3
commit
07e0974f2c
10
dwarves.c
10
dwarves.c
|
@ -1831,7 +1831,15 @@ void class__find_holes(struct class *self, const struct cu *cu)
|
|||
continue;
|
||||
|
||||
if (last != NULL) {
|
||||
const ssize_t cc_last_size = pos->offset - last->offset;
|
||||
/*
|
||||
* We have to cast both offsets to int64_t because
|
||||
* the current offset can be before the last offset
|
||||
* in some bitfield cases at least with gcc as
|
||||
* was the case with struct usb_bus field is_b_host in
|
||||
* the linux kernel circa 2.6.24-rc3.
|
||||
*/
|
||||
const ssize_t cc_last_size = ((int64_t)pos->offset -
|
||||
(int64_t)last->offset);
|
||||
|
||||
/*
|
||||
* If the offset is the same this better be a bitfield
|
||||
|
|
Loading…
Reference in New Issue