Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: Martin KaFai Lau <kafai@fb.com>
- Loading branch information
Showing
7 changed files
with
877 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ | ||
/* Copyright (c) 2018 Facebook */ | ||
#ifndef _UAPI__LINUX_BTF_H__ | ||
#define _UAPI__LINUX_BTF_H__ | ||
|
||
#include <linux/types.h> | ||
|
||
#define BTF_MAGIC 0xeB9F | ||
#define BTF_VERSION 1 | ||
|
||
struct btf_header { | ||
__u16 magic; | ||
__u8 version; | ||
__u8 flags; | ||
__u32 hdr_len; | ||
|
||
/* All offsets are in bytes relative to the end of this header */ | ||
__u32 type_off; /* offset of type section */ | ||
__u32 type_len; /* length of type section */ | ||
__u32 str_off; /* offset of string section */ | ||
__u32 str_len; /* length of string section */ | ||
}; | ||
|
||
/* Max # of type identifier */ | ||
#define BTF_MAX_TYPE 0x0000ffff | ||
/* Max offset into the string section */ | ||
#define BTF_MAX_NAME_OFFSET 0x0000ffff | ||
/* Max # of struct/union/enum members or func args */ | ||
#define BTF_MAX_VLEN 0xffff | ||
|
||
struct btf_type { | ||
__u32 name_off; | ||
/* "info" bits arrangement | ||
* bits 0-15: vlen (e.g. # of struct's members) | ||
* bits 16-23: unused | ||
* bits 24-27: kind (e.g. int, ptr, array...etc) | ||
* bits 28-31: unused | ||
*/ | ||
__u32 info; | ||
/* "size" is used by INT, ENUM, STRUCT and UNION. | ||
* "size" tells the size of the type it is describing. | ||
* | ||
* "type" is used by PTR, TYPEDEF, VOLATILE, CONST and RESTRICT. | ||
* "type" is a type_id referring to another type. | ||
*/ | ||
union { | ||
__u32 size; | ||
__u32 type; | ||
}; | ||
}; | ||
|
||
#define BTF_INFO_KIND(info) (((info) >> 24) & 0x0f) | ||
#define BTF_INFO_VLEN(info) ((info) & 0xffff) | ||
|
||
#define BTF_KIND_UNKN 0 /* Unknown */ | ||
#define BTF_KIND_INT 1 /* Integer */ | ||
#define BTF_KIND_PTR 2 /* Pointer */ | ||
#define BTF_KIND_ARRAY 3 /* Array */ | ||
#define BTF_KIND_STRUCT 4 /* Struct */ | ||
#define BTF_KIND_UNION 5 /* Union */ | ||
#define BTF_KIND_ENUM 6 /* Enumeration */ | ||
#define BTF_KIND_FWD 7 /* Forward */ | ||
#define BTF_KIND_TYPEDEF 8 /* Typedef */ | ||
#define BTF_KIND_VOLATILE 9 /* Volatile */ | ||
#define BTF_KIND_CONST 10 /* Const */ | ||
#define BTF_KIND_RESTRICT 11 /* Restrict */ | ||
#define BTF_KIND_MAX 11 | ||
#define NR_BTF_KINDS 12 | ||
|
||
/* For some specific BTF_KIND, "struct btf_type" is immediately | ||
* followed by extra data. | ||
*/ | ||
|
||
/* BTF_KIND_INT is followed by a u32 and the following | ||
* is the 32 bits arrangement: | ||
*/ | ||
#define BTF_INT_ENCODING(VAL) (((VAL) & 0x0f000000) >> 24) | ||
#define BTF_INT_OFFSET(VAL) (((VAL & 0x00ff0000)) >> 16) | ||
#define BTF_INT_BITS(VAL) ((VAL) & 0x0000ffff) | ||
|
||
/* Attributes stored in the BTF_INT_ENCODING */ | ||
#define BTF_INT_SIGNED (1 << 0) | ||
#define BTF_INT_CHAR (1 << 1) | ||
#define BTF_INT_BOOL (1 << 2) | ||
|
||
/* BTF_KIND_ENUM is followed by multiple "struct btf_enum". | ||
* The exact number of btf_enum is stored in the vlen (of the | ||
* info in "struct btf_type"). | ||
*/ | ||
struct btf_enum { | ||
__u32 name_off; | ||
__s32 val; | ||
}; | ||
|
||
/* BTF_KIND_ARRAY is followed by one "struct btf_array" */ | ||
struct btf_array { | ||
__u32 type; | ||
__u32 index_type; | ||
__u32 nelems; | ||
}; | ||
|
||
/* BTF_KIND_STRUCT and BTF_KIND_UNION are followed | ||
* by multiple "struct btf_member". The exact number | ||
* of btf_member is stored in the vlen (of the info in | ||
* "struct btf_type"). | ||
*/ | ||
struct btf_member { | ||
__u32 name_off; | ||
__u32 type; | ||
__u32 offset; /* offset in bits */ | ||
}; | ||
|
||
#endif /* _UAPI__LINUX_BTF_H__ */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,174 @@ | ||
#include "dwarves.h" | ||
#include "libbtf.h" | ||
#include "btf.h" | ||
#include "hash.h" | ||
#include "elf_symtab.h" | ||
#include "btf_encoder.h" | ||
|
||
#include <inttypes.h> | ||
|
||
static int tag__check_id_drift(const struct tag *tag, | ||
uint32_t core_id, uint32_t btf_type_id) | ||
{ | ||
if (btf_type_id != core_id) { | ||
fprintf(stderr, "%s: %s id drift, core_id: %u, btf_type_id: %u\n", | ||
__func__, dwarf_tag_name(tag->tag), | ||
core_id, btf_type_id); | ||
return -1; | ||
} | ||
|
||
return 0; | ||
} | ||
|
||
static int32_t structure_type__encode(struct btf *btf, struct tag *tag) | ||
{ | ||
struct type *type = tag__type(tag); | ||
struct class_member *pos; | ||
int32_t type_id; | ||
uint8_t kind; | ||
|
||
kind = (tag->tag == DW_TAG_union_type) ? | ||
BTF_KIND_UNION : BTF_KIND_STRUCT; | ||
type_id = btf__add_struct(btf, kind, type->namespace.name, | ||
type->size, type->nr_members); | ||
if (type_id < 0) | ||
return type_id; | ||
|
||
type__for_each_data_member(type, pos) | ||
if (btf__add_member(btf, pos->name, pos->tag.type, | ||
pos->bit_offset)) | ||
return -1; | ||
|
||
return type_id; | ||
} | ||
|
||
static uint32_t array_type__nelems(struct tag *tag) | ||
{ | ||
int i; | ||
uint32_t nelem = 1; | ||
struct array_type *array = tag__array_type(tag); | ||
|
||
for (i = array->dimensions - 1; i >= 0; --i) | ||
nelem *= array->nr_entries[i]; | ||
|
||
return nelem; | ||
} | ||
|
||
static int32_t enumeration_type__encode(struct btf *btf, struct tag *tag) | ||
{ | ||
struct type *etype = tag__type(tag); | ||
struct enumerator *pos; | ||
int32_t type_id; | ||
|
||
type_id = btf__add_enum(btf, etype->namespace.name, | ||
etype->size, etype->nr_members); | ||
if (type_id < 0) | ||
return type_id; | ||
|
||
type__for_each_enumerator(etype, pos) | ||
if (btf__add_enum_val(btf, pos->name, pos->value)) | ||
return -1; | ||
|
||
return type_id; | ||
} | ||
|
||
static int tag__encode_btf(struct tag *tag, uint32_t core_id, struct btf *btf, | ||
uint32_t array_index_id) | ||
{ | ||
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); | ||
case DW_TAG_pointer_type: | ||
return btf__add_ref_type(btf, BTF_KIND_PTR, tag->type, 0); | ||
case DW_TAG_restrict_type: | ||
return btf__add_ref_type(btf, BTF_KIND_RESTRICT, tag->type, 0); | ||
case DW_TAG_volatile_type: | ||
return btf__add_ref_type(btf, BTF_KIND_VOLATILE, tag->type, 0); | ||
case DW_TAG_typedef: | ||
return btf__add_ref_type(btf, BTF_KIND_TYPEDEF, tag->type, | ||
tag__namespace(tag)->name); | ||
case DW_TAG_structure_type: | ||
case DW_TAG_union_type: | ||
case DW_TAG_class_type: | ||
if (tag__type(tag)->declaration) | ||
return btf__add_ref_type(btf, BTF_KIND_FWD, 0, | ||
tag__namespace(tag)->name); | ||
else | ||
return structure_type__encode(btf, tag); | ||
case DW_TAG_array_type: | ||
return btf__add_array(btf, tag->type, array_index_id, | ||
/*TODO: Encode one dimension | ||
* at a time. | ||
*/ | ||
array_type__nelems(tag)); | ||
case DW_TAG_enumeration_type: | ||
return enumeration_type__encode(btf, tag); | ||
case DW_TAG_subroutine_type: | ||
/* A dummy void * to avoid a shift in btf->type_index */ | ||
btf_verbose_log("Filling unsupported DW_TAG_%s(0x%x) with void *\n", | ||
dwarf_tag_name(tag->tag), tag->tag); | ||
return btf__add_ref_type(btf, BTF_KIND_PTR, 0, 0); | ||
default: | ||
fprintf(stderr, "Unsupported DW_TAG_%s(0x%x)\n", | ||
dwarf_tag_name(tag->tag), tag->tag); | ||
return -1; | ||
} | ||
} | ||
|
||
/* | ||
* FIXME: Its in the DWARF loader, we have to find a better handoff | ||
* mechanizm... | ||
*/ | ||
extern struct strings *strings; | ||
|
||
int cu__encode_btf(struct cu *cu, int verbose) | ||
{ | ||
struct btf *btf = btf__new(cu->filename, cu->elf); | ||
struct tag *pos; | ||
uint32_t core_id, array_index_id; | ||
uint16_t id; | ||
int err; | ||
|
||
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; | ||
|
||
cu__for_each_type(cu, core_id, pos) { | ||
int32_t btf_type_id = tag__encode_btf(pos, core_id, btf, | ||
array_index_id); | ||
|
||
if (btf_type_id < 0 || | ||
tag__check_id_drift(pos, core_id, btf_type_id)) { | ||
err = -1; | ||
goto out; | ||
} | ||
|
||
id = btf_type_id; | ||
} | ||
|
||
if (array_index_id == cu->types_table.nr_entries) { | ||
struct base_type bt = {}; | ||
|
||
bt.name = 0; | ||
bt.bit_size = 32; | ||
btf__add_base_type(btf, &bt); | ||
} | ||
|
||
err = btf__encode(btf, 0); | ||
|
||
out: | ||
btf__free(btf); | ||
if (err) | ||
fprintf(stderr, "Failed to encode BTF\n"); | ||
return err; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
#ifndef _BTF_ENCODER_H_ | ||
#define _BTF_ENCODER_H_ 1 | ||
|
||
struct cu; | ||
|
||
int cu__encode_btf(struct cu *cu, int verbose); | ||
|
||
#endif /* _BTF_ENCODER_H_ */ |
Oops, something went wrong.