btf: Allow multiple cu's in dwarf->btf conversion
Currently, the pahole dwarf->btf conversion only supports one compilation unit. This is not ideal since we would like using pahole to generate BTF for vmlinux which has a lot of compilation units. This patch added support to process multiple compilation units per ELF file. Multiple ELF files are also supported properly. The following is a demonstration example: -bash-4.4$ cat t1.c struct t1 { int a1; } g1; int main(void) { return 0; } -bash-4.4$ cat t2.c struct t2 { char a2; } g2; int main() { return 0; } -bash-4.4$ cat t3.c struct t3 { unsigned char a1:4; } g1; int main(void) { return 0; } -bash-4.4$ cat t4.c struct t4 { volatile char a4; } g2; int main() { return 0; } -bash-4.4$ gcc -O2 -o t1 -g t1.c t2.c -bash-4.4$ gcc -O2 -o t3 -g t3.c t4.c Note that both the binary "t1" and "t3" have two compilation units in their respective dwarf debug_info sections. The following is the pahole verbose output for BTF conversion for these two binaries. -bash-4.4$ pahole -JV t1 t3 File t1: [1] STRUCT t1 size=4 vlen=1 a1 type_id=2 bits_offset=0 [2] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED [3] STRUCT t2 size=1 vlen=1 a2 type_id=4 bits_offset=0 [4] INT char size=1 bit_offset=0 nr_bits=8 encoding=(none) [5] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED File t3: [1] STRUCT t3 size=1 vlen=1 a1 type_id=3 bits_offset=0 [2] INT unsigned char size=1 bit_offset=0 nr_bits=8 encoding=(none) [3] INT unsigned char size=1 bit_offset=0 nr_bits=4 encoding=(none) [4] INT (anon) size=4 bit_offset=0 nr_bits=32 encoding=(none) [5] STRUCT t4 size=1 vlen=1 a4 type_id=6 bits_offset=0 [6] VOLATILE (anon) type_id=7 [7] INT char size=1 bit_offset=0 nr_bits=8 encoding=(none) [8] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED Signed-off-by: Andrii Nakryiko <andriin@fb.com> Acked-by: Martin KaFai Lau <kafai@fb.com> Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Alexei Starovoitov <ast@fb.com> Cc: Yonghong Song <yhs@fb.com> Signed-off-by: Yonghong Song <yhs@fb.com> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
parent
d843945ba5
commit
65bd17abc7
112
btf_encoder.c
112
btf_encoder.c
|
@ -8,19 +8,22 @@
|
|||
#include <inttypes.h>
|
||||
|
||||
static int tag__check_id_drift(const struct tag *tag,
|
||||
uint32_t core_id, uint32_t btf_type_id)
|
||||
uint32_t core_id, uint32_t btf_type_id,
|
||||
uint32_t type_id_off)
|
||||
{
|
||||
if (btf_type_id != core_id) {
|
||||
fprintf(stderr, "%s: %s id drift, core_id: %u, btf_type_id: %u\n",
|
||||
if (btf_type_id != (core_id + type_id_off)) {
|
||||
fprintf(stderr,
|
||||
"%s: %s id drift, core_id: %u, btf_type_id: %u, type_id_off: %u\n",
|
||||
__func__, dwarf_tag_name(tag->tag),
|
||||
core_id, btf_type_id);
|
||||
core_id, btf_type_id, type_id_off);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t structure_type__encode(struct btf *btf, struct tag *tag)
|
||||
static int32_t structure_type__encode(struct btf *btf, struct tag *tag,
|
||||
uint32_t type_id_off)
|
||||
{
|
||||
struct type *type = tag__type(tag);
|
||||
struct class_member *pos;
|
||||
|
@ -59,7 +62,8 @@ static int32_t structure_type__encode(struct btf *btf, struct tag *tag)
|
|||
pos->bitfield_offset -
|
||||
pos->bitfield_size;
|
||||
|
||||
if (btf__add_member(btf, pos->name, pos->tag.type,
|
||||
if (btf__add_member(btf, pos->name,
|
||||
type_id_off + pos->tag.type,
|
||||
bit_offset))
|
||||
return -1;
|
||||
}
|
||||
|
@ -107,21 +111,24 @@ static int32_t enumeration_type__encode(struct btf *btf, struct tag *tag)
|
|||
}
|
||||
|
||||
static int tag__encode_btf(struct tag *tag, uint32_t core_id, struct btf *btf,
|
||||
uint32_t array_index_id)
|
||||
uint32_t array_index_id, uint32_t type_id_off)
|
||||
{
|
||||
/* single out type 0 as it represents special type "void" */
|
||||
uint32_t ref_type_id = tag->type == 0 ? 0 : type_id_off + tag->type;
|
||||
|
||||
switch (tag->tag) {
|
||||
case DW_TAG_base_type:
|
||||
return btf__add_base_type(btf, tag__base_type(tag));
|
||||
case DW_TAG_const_type:
|
||||
return btf__add_ref_type(btf, BTF_KIND_CONST, tag->type, 0);
|
||||
return btf__add_ref_type(btf, BTF_KIND_CONST, ref_type_id, 0);
|
||||
case DW_TAG_pointer_type:
|
||||
return btf__add_ref_type(btf, BTF_KIND_PTR, tag->type, 0);
|
||||
return btf__add_ref_type(btf, BTF_KIND_PTR, ref_type_id, 0);
|
||||
case DW_TAG_restrict_type:
|
||||
return btf__add_ref_type(btf, BTF_KIND_RESTRICT, tag->type, 0);
|
||||
return btf__add_ref_type(btf, BTF_KIND_RESTRICT, ref_type_id, 0);
|
||||
case DW_TAG_volatile_type:
|
||||
return btf__add_ref_type(btf, BTF_KIND_VOLATILE, tag->type, 0);
|
||||
return btf__add_ref_type(btf, BTF_KIND_VOLATILE, ref_type_id, 0);
|
||||
case DW_TAG_typedef:
|
||||
return btf__add_ref_type(btf, BTF_KIND_TYPEDEF, tag->type,
|
||||
return btf__add_ref_type(btf, BTF_KIND_TYPEDEF, ref_type_id,
|
||||
tag__namespace(tag)->name);
|
||||
case DW_TAG_structure_type:
|
||||
case DW_TAG_union_type:
|
||||
|
@ -130,9 +137,9 @@ static int tag__encode_btf(struct tag *tag, uint32_t core_id, struct btf *btf,
|
|||
return btf__add_ref_type(btf, BTF_KIND_FWD, 0,
|
||||
tag__namespace(tag)->name);
|
||||
else
|
||||
return structure_type__encode(btf, tag);
|
||||
return structure_type__encode(btf, tag, type_id_off);
|
||||
case DW_TAG_array_type:
|
||||
return btf__add_array(btf, tag->type, array_index_id,
|
||||
return btf__add_array(btf, ref_type_id, array_index_id,
|
||||
/*TODO: Encode one dimension
|
||||
* at a time.
|
||||
*/
|
||||
|
@ -157,40 +164,72 @@ static int tag__encode_btf(struct tag *tag, uint32_t core_id, struct btf *btf,
|
|||
*/
|
||||
extern struct strings *strings;
|
||||
|
||||
int cu__encode_btf(struct cu *cu, int verbose)
|
||||
static struct btf *btf;
|
||||
static uint32_t array_index_id;
|
||||
|
||||
int btf_encoder__encode()
|
||||
{
|
||||
struct btf *btf = btf__new(cu->filename, cu->elf);
|
||||
struct tag *pos;
|
||||
uint32_t core_id, array_index_id;
|
||||
uint16_t id;
|
||||
int err;
|
||||
|
||||
err = btf__encode(btf, 0);
|
||||
btf__free(btf);
|
||||
btf = NULL;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int cu__encode_btf(struct cu *cu, int verbose)
|
||||
{
|
||||
bool add_index_type = false;
|
||||
uint32_t type_id_off;
|
||||
uint32_t core_id;
|
||||
struct tag *pos;
|
||||
int err = 0;
|
||||
|
||||
if (btf && strcmp(btf->filename, cu->filename)) {
|
||||
err = btf_encoder__encode();
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
/* Finished one file, add one empty line */
|
||||
if (verbose)
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
if (!btf) {
|
||||
btf = btf__new(cu->filename, cu->elf);
|
||||
if (!btf)
|
||||
return -1;
|
||||
btf__set_strings(btf, &strings->gb);
|
||||
|
||||
/* cu__find_base_type_by_name() takes "uint16_t *id" */
|
||||
uint16_t id;
|
||||
if (!cu__find_base_type_by_name(cu, "int", &id)) {
|
||||
add_index_type = true;
|
||||
id = cu->types_table.nr_entries;
|
||||
}
|
||||
array_index_id = id;
|
||||
|
||||
if (verbose)
|
||||
printf("File %s:\n", btf->filename);
|
||||
}
|
||||
|
||||
btf_verbose = verbose;
|
||||
|
||||
if (btf == NULL)
|
||||
return -1;
|
||||
|
||||
btf__set_strings(btf, &strings->gb);
|
||||
|
||||
/* cu__find_base_type_by_name() takes "uint16_t *id" */
|
||||
if (!cu__find_base_type_by_name(cu, "int", &id))
|
||||
id = cu->types_table.nr_entries;
|
||||
array_index_id = id;
|
||||
type_id_off = btf->type_index;
|
||||
|
||||
cu__for_each_type(cu, core_id, pos) {
|
||||
int32_t btf_type_id = tag__encode_btf(pos, core_id, btf,
|
||||
array_index_id);
|
||||
array_index_id,
|
||||
type_id_off);
|
||||
|
||||
if (btf_type_id < 0 ||
|
||||
tag__check_id_drift(pos, core_id, btf_type_id)) {
|
||||
tag__check_id_drift(pos, core_id, btf_type_id, type_id_off)) {
|
||||
err = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
id = btf_type_id;
|
||||
}
|
||||
|
||||
if (array_index_id == cu->types_table.nr_entries) {
|
||||
if (add_index_type) {
|
||||
struct base_type bt = {};
|
||||
|
||||
bt.name = 0;
|
||||
|
@ -198,11 +237,8 @@ int cu__encode_btf(struct cu *cu, int verbose)
|
|||
btf__add_base_type(btf, &bt);
|
||||
}
|
||||
|
||||
err = btf__encode(btf, 0);
|
||||
|
||||
out:
|
||||
btf__free(btf);
|
||||
if (err)
|
||||
fprintf(stderr, "Failed to encode BTF\n");
|
||||
btf__free(btf);
|
||||
return err;
|
||||
}
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
struct cu;
|
||||
|
||||
int btf_encoder__encode();
|
||||
|
||||
int cu__encode_btf(struct cu *cu, int verbose);
|
||||
|
||||
#endif /* _BTF_ENCODER_H_ */
|
||||
|
|
2
libbtf.c
2
libbtf.c
|
@ -509,7 +509,7 @@ int btf__encode(struct btf *btf, uint8_t flags)
|
|||
hdr = btf->hdr;
|
||||
hdr->magic = BTF_MAGIC;
|
||||
hdr->version = 1;
|
||||
hdr->flags = 0;
|
||||
hdr->flags = flags;
|
||||
hdr->hdr_len = sizeof(*hdr);
|
||||
|
||||
hdr->type_off = 0;
|
||||
|
|
10
pahole.c
10
pahole.c
|
@ -1115,7 +1115,7 @@ static enum load_steal_kind pahole_stealer(struct cu *cu,
|
|||
|
||||
if (btf_encode) {
|
||||
cu__encode_btf(cu, global_verbose);
|
||||
goto dump_and_stop;
|
||||
return LSK__KEEPIT;
|
||||
}
|
||||
|
||||
if (ctf_encode) {
|
||||
|
@ -1265,6 +1265,14 @@ int main(int argc, char *argv[])
|
|||
goto out_cus_delete;
|
||||
}
|
||||
|
||||
if (btf_encode) {
|
||||
err = btf_encoder__encode();
|
||||
if (err) {
|
||||
fputs("Failed to encode BTF\n", stderr);
|
||||
goto out_cus_delete;
|
||||
}
|
||||
}
|
||||
|
||||
if (stats_formatter != NULL)
|
||||
print_stats();
|
||||
rc = EXIT_SUCCESS;
|
||||
|
|
Loading…
Reference in New Issue