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>
The latest elfutils-libelf headers won't compile without _LARGEFILE64_SOURCE
(that is implied by _GNU_SOURCE).
Some .c files don't have a #define _GNU_SOURCE line. Instead of adding the line
to all .c files, define it globally on CMakeLists.txt.
Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
Will just print the vtable as a comment on classes with vtables.
But we have to support multiple vtables when multiple inheritance exists.
Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
So that we can also look for offset expressions other than DW_AT_data_member_location.
Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
Another C++ specific case:
- class TypeTemplate ByName(const string &, size_t);
+ class TypeTemplate ByName(const string &, size_t); /* linkage=_ZN4ROOT6Reflex12TypeTemplate6ByNameERKSsj */
Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
More C++ support. Now we print "virtual" before DW_TAG_subprogram DW_TAG_member
tags that have a DW_AT_virtuality attribute of and DW_VIRTUALITY_pure_virtual or
DW_VIRTUALITY_virtual and " = 0" after the DW_VIRTUALITY_pure_virtual ones.
vtables are next.
Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
class__fprintf_cacheline_boundary should only be called if
conf_suppress_comments is not set.
Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
And use it when expandind pointer types (using --expand_pointer).
This has to be done because the offset comments make no sense when expanding a
pointer.
Will be used as well in pahole --quiet.
Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
So that we can expand pointer types, useful for ABI signature checking. And to
fully browse a type, when using --expand_types is also of interest.
I have yet to disable printing the offsets when expanding pointers, where the
information is not useful at all, for now just ignore it, it gets back to a
sane state in the next field, after the pointer type expansion.
Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
For now it just suppresses the struct statistics at the end of the output, but
will also suppress the comments about holes.
Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
To indicate wheter the semicolon should be supressed. Useful for
prototype/function emission, etc.
Also move the struct stats to be inside its body, to simplify tag__fprintf,
that now looks at conf.no_semicolon after calling the tag type specific
__fprintf method.
Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
So that tools can specify if they are interested in printing just the members
that use space in the class layout (DW_TAG_inheritance, DW_TAG_member) and not
things like constructors, private type definitions, etc.
Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
So far we only handle DW_OP_plus_uconst, the simplest of them all, but now
'public virtual' base classes are appearing in these tools radar, so, to make
it clear that we don't support it spit a warning message to stderr and return
UINT64_MAX so that in the report it is clearly seen. C++ support still needs
more work, simple as that :)
Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
So that we traverse just the data members, mostly in the reorganize code, where
we can't care less where is that the compiler put the base classes in the
layout since we can't influence how the compiler does this, it has only to
respect the layout we specify for the data members.
Well, it may well be the case that the order of the ancestor classes in the
class declaration can influence this, but I haven't checked.
Yes, another C++ism :-)
Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
This is simplified by introducing list__find_tag_by_id. I guess in the end the
right thing is to use a hashtable to find the ids. Trying to have specialized
find_foo_by_id functions instead of having just one that traverses _all_ the
tags is becoming less of a performance advantage as struct class now has
namespaces, i.e. functions can be inside structs and to find abstract_origin,
specification, etc references we have to traverse most of the tree anyway...
Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
Heck, anonymous structs are nothing new, things like:
typedef struct {
int bar;
} baz;
Are ugly, but valid. So if ->name is NULL and ->specification is 0, its an
anonymous struct, don't go looking for dwarf offset 0, that is "void", not
something a DW_AT_specification is supposed to point to 8)
Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
tag__type_not_found was incorrectly being used for cases where we were
searching things like abstract_origin and specification, not tag->type, so add
this variant, make tag__type_not_found use id and fix the callers.
Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>