Skip to content

Commit 1ee069f

Browse files
committed
ctf: explicitly specify the sizes of structures and unions
Before now, we have allowed libdtrace-ctf to decide what size a structure or union is, given the alignment and packing requirements of the members. However, this is flawed: the alignment and packing requirements are platform-dependent, and libdtrace-ctf has no idea what those requirements are: and for packed structures they are certain to be wrong anyway. The DWARF already encodes precisely how large all these things are: we even collect and use this information to disambiguate otherwise- identical structures (e.g. those modified by #ifdefs that vary by translation unit). So refactor this code out into a new private_dwarf_size() function and use it both from the old place in type_id() and from assemble_ctf_struct_union(). If no size is specified, or if the compiler has elected to use a form that we cannot handle (like, say, an exprloc, which we are *not* interpreting), let libdtrace-ctf figure it out, but otherwise -- in the vast majority of cases -- explicitly specify it. Explicit specification of sizes requires libdtrace-ctf 1.1, which this commit thus requires. (This also adds some suitable structures to the dt_test module so that the DTrace testsuite can verify that this change does not regress.) Signed-off-by: Nick Alcock <[email protected]> Reviewed-by: Kris Van Hees <[email protected]> Orabug: 29054989
1 parent 5270c14 commit 1ee069f

File tree

3 files changed

+112
-38
lines changed

3 files changed

+112
-38
lines changed

dtrace/dt_test_dev.c

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* FILE: dt_test_dev.c
33
* DESCRIPTION: DTrace - test provider device driver
44
*
5-
* Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved.
5+
* Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
66
*
77
* This program is free software; you can redistribute it and/or modify
88
* it under the terms of the GNU General Public License as published by
@@ -17,6 +17,7 @@
1717

1818
#include <linux/fs.h>
1919
#include <linux/miscdevice.h>
20+
#include <linux/types.h>
2021
#include <trace/syscall.h>
2122
#include <asm/unistd.h>
2223

@@ -27,6 +28,44 @@
2728
static dtrace_id_t pid = DTRACE_IDNONE;
2829
static int enabled = 0;
2930

31+
/*
32+
* Some arrays of structures of different sizes populated with
33+
* unchanging randomly-chosen numbers, for padding tests.
34+
*/
35+
36+
static struct dt_test_int_char
37+
{
38+
int foo;
39+
char bar;
40+
} intish[2] __attribute__((used)) = { { 47204473, 48 },
41+
{ 18472, 62 } };
42+
43+
static struct dt_test_long_int
44+
{
45+
long foo;
46+
int bar;
47+
} longish[2] __attribute__((used)) = { { 43737975, 240724 },
48+
{ 24924709, 526 } };
49+
50+
static struct dt_test_longlong_long
51+
{
52+
long long foo;
53+
long bar;
54+
} longlongish[2] __attribute__((used)) = { { 4294479287, 4395957 },
55+
{ 5239637, 249750 } };
56+
57+
static struct dt_test_like_a_scatterlist
58+
{
59+
unsigned long a;
60+
unsigned int b;
61+
unsigned int c;
62+
u64 d;
63+
unsigned int e;
64+
} scatter_failure[2] __attribute__((used)) = { { .a = 1, .b = 2,
65+
.c = 3, .d = 4, .e = 5 },
66+
{ .a = 6, .b = 7,
67+
.c = 8, .d = 9, .e = 10 } };
68+
3069
void dt_test_provide(void *arg, const dtrace_probedesc_t *desc)
3170
{
3271
if (dtrace_probe_lookup(dt_test_id, "dt_test", NULL, "test") != DTRACE_IDNONE)

scripts/dwarf2ctf/dwarf2ctf.c

Lines changed: 70 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -773,6 +773,12 @@ static inline Dwarf_Attribute *private_dwarf_attr(Dwarf_Die *die,
773773
static inline Dwarf_Word private_dwarf_udata(Dwarf_Die *die, int attribute,
774774
die_override_t *overrides);
775775

776+
/*
777+
* Given a DIE, return its byte size, if known and interpretable, or -1
778+
* otherwise.
779+
*/
780+
static inline long long private_dwarf_size(Dwarf_Die *die);
781+
776782
/*
777783
* Find an override in an override list.
778784
*/
@@ -1631,11 +1637,11 @@ static char *type_id(Dwarf_Die *die,
16311637
case DW_TAG_structure_type:
16321638
case DW_TAG_union_type: {
16331639
/*
1634-
* Incorporate the sizeof() the structure, if statically known
1635-
* (the offset of the last member in the DWARF) so that most
1636-
* structures which are redefined on the fly by preprocessor
1637-
* defines are disambiguated despite being defined in the same
1638-
* place.
1640+
* Incorporate the unaligned sizeof() the structure, if
1641+
* statically known (the offset of the last member in the DWARF)
1642+
* so that most structures which are redefined on the fly by
1643+
* preprocessor defines are disambiguated despite being defined
1644+
* in the same place.
16391645
*
16401646
* Only do this if this is a non-opaque structure/union
16411647
* definition: opaque definitions cannot have a size, but if
@@ -1646,35 +1652,12 @@ static char *type_id(Dwarf_Die *die,
16461652
*/
16471653
const char *sou;
16481654

1649-
if (strncmp(id, "////", 4) != 0 &&
1650-
private_dwarf_hasattr(die, DW_AT_byte_size)) {
1651-
Dwarf_Attribute size_attr;
1655+
if (strncmp(id, "////", 4) != 0) {
16521656
long long size;
16531657
char byte_size[24];
16541658

1655-
private_dwarf_attr(die, DW_AT_byte_size, &size_attr);
1656-
1657-
switch (dwarf_whatform(&size_attr)) {
1658-
case DW_FORM_data1:
1659-
case DW_FORM_data2:
1660-
case DW_FORM_data4:
1661-
case DW_FORM_data8:
1662-
case DW_FORM_udata:
1663-
case DW_FORM_sdata:
1664-
1665-
if (dwarf_whatform(&size_attr) ==
1666-
DW_FORM_sdata) {
1667-
Dwarf_Sword dw_size;
1668-
1669-
dwarf_formsdata(&size_attr, &dw_size);
1670-
size = dw_size;
1671-
} else {
1672-
Dwarf_Word dw_size;
1673-
1674-
dwarf_formudata(&size_attr, &dw_size);
1675-
size = dw_size;
1676-
}
1677-
1659+
size = private_dwarf_size(die);
1660+
if (size > -1) {
16781661
sprintf(byte_size, "%lli", size);
16791662
id = str_appendn(id, byte_size, "//", NULL);
16801663
}
@@ -3669,19 +3652,33 @@ static ctf_id_t assemble_ctf_struct_union(const char *module_name,
36693652
enum skip_type *skip,
36703653
int *replace)
36713654
{
3672-
ctf_id_t (*ctf_add_sou)(ctf_file_t *, uint_t, const char *);
3655+
ctf_id_t (*ctf_add_sou)(ctf_file_t *, uint_t, const char *, size_t);
36733656

36743657
const char *name = dwarf_diename(die);
36753658
int is_union = (dwarf_tag(die) == DW_TAG_union_type);
36763659
ctf_memb_count_t *member_count = NULL;
36773660
ctf_id_t id;
3661+
long long size;
36783662

36793663
/*
36803664
* FIXME: these both need handling for DWARF4 support.
36813665
*/
36823666
CTF_DW_ENFORCE_NOT(specification);
36833667
CTF_DW_ENFORCE_NOT(signature);
36843668

3669+
/*
3670+
* Figure out the size of the type (if possible) and force it into the
3671+
* CTF to ensure that struct/union padding is added appropriately.
3672+
*
3673+
* If we don't know it, force a size of zero, which is interpreted as
3674+
* being equivalent to a call to the unsized struct/union addition
3675+
* function, letting libdtrace-ctf figure out a likely size as best it
3676+
* can.
3677+
*/
3678+
size = private_dwarf_size(die);
3679+
if (size < 0)
3680+
size = 0;
3681+
36853682
/*
36863683
* Possibly we should ignore this entire structure, if we already know
36873684
* of one with the same name and at least as many members. If we
@@ -3736,13 +3733,14 @@ static ctf_id_t assemble_ctf_struct_union(const char *module_name,
37363733
}
37373734

37383735
dw_ctf_trace("%s: adding structure %s\n", locerrstr, name);
3736+
37393737
if (is_union)
3740-
ctf_add_sou = ctf_add_union;
3738+
ctf_add_sou = ctf_add_union_sized;
37413739
else
3742-
ctf_add_sou = ctf_add_struct;
3740+
ctf_add_sou = ctf_add_struct_sized;
37433741

37443742
id = ctf_add_sou(ctf, top_level_type ? CTF_ADD_ROOT : CTF_ADD_NONROOT,
3745-
name);
3743+
name, size);
37463744

37473745
if (member_count != NULL)
37483746
member_count->ctf_id = id;
@@ -4413,6 +4411,43 @@ static inline Dwarf_Word private_dwarf_udata(Dwarf_Die *die, int attribute,
44134411
return value;
44144412
}
44154413

4414+
/*
4415+
* Given a DIE, return its byte size, if known and interpretable, or -1
4416+
* otherwise.
4417+
*/
4418+
static inline long long private_dwarf_size(Dwarf_Die *die)
4419+
{
4420+
Dwarf_Attribute size_attr;
4421+
4422+
if (private_dwarf_hasattr(die, DW_AT_byte_size)) {
4423+
private_dwarf_attr(die, DW_AT_byte_size, &size_attr);
4424+
4425+
switch (dwarf_whatform(&size_attr)) {
4426+
case DW_FORM_data1:
4427+
case DW_FORM_data2:
4428+
case DW_FORM_data4:
4429+
case DW_FORM_data8:
4430+
case DW_FORM_udata: {
4431+
Dwarf_Word dw_size;
4432+
4433+
dwarf_formudata(&size_attr, &dw_size);
4434+
return dw_size;
4435+
}
4436+
case DW_FORM_sdata: {
4437+
Dwarf_Sword dw_size;
4438+
4439+
dwarf_formsdata(&size_attr, &dw_size);
4440+
return dw_size;
4441+
}
4442+
}
4443+
}
4444+
4445+
/*
4446+
* exprloc or other type we don't know how to interpret yet.
4447+
*/
4448+
return -1;
4449+
}
4450+
44164451
/*
44174452
* Find an override in an override list, walking up the chained overrides if
44184453
* need be, until one is found.

uek-rpm/ol7/kernel-uek.spec

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -558,7 +558,7 @@ BuildRequires: pesign >= 0.10-4
558558
BuildRequires: hmaccalc
559559
%endif
560560
%if %{with_dtrace}
561-
BuildRequires: libdtrace-ctf-devel >= 0.8.0
561+
BuildRequires: libdtrace-ctf-devel >= 1.1.0
562562
%endif
563563
%if %{with_perf_tui}
564564
BuildRequires: slang-devel, slang-static
@@ -864,7 +864,7 @@ Requires(pre): /usr/bin/find\
864864
Requires: elfutils-libelf >= 0.160\
865865
Requires: elfutils-libs >= 0.160\
866866
%if %{with_dtrace}\
867-
Requires: libdtrace-ctf >= 0.8.0\
867+
Requires: libdtrace-ctf >= 1.1.0\
868868
%endif\
869869
%description -n kernel%{?variant}%{?1:-%{1}}-devel\
870870
This package provides kernel headers and makefiles sufficient to build modules\

0 commit comments

Comments
 (0)