[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:
Arnaldo Carvalho de Melo 2007-12-06 21:59:42 -02:00
parent be79835bf3
commit 07e0974f2c
1 changed files with 9 additions and 1 deletions

View File

@ -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