Skip to content

Commit

Permalink
btf: Add BTF support
Browse files Browse the repository at this point in the history
Signed-off-by: Martin KaFai Lau <kafai@fb.com>
  • Loading branch information
iamkafai committed Jun 5, 2018
1 parent 81466af commit 94a11b5
Show file tree
Hide file tree
Showing 7 changed files with 877 additions and 2 deletions.
4 changes: 2 additions & 2 deletions CMakeLists.txt
Expand Up @@ -34,8 +34,8 @@ find_package(ZLIB REQUIRED)
_set_fancy(LIB_INSTALL_DIR "${EXEC_INSTALL_PREFIX}${CMAKE_INSTALL_PREFIX}/${__LIB}" "libdir")

set(dwarves_LIB_SRCS dwarves.c dwarves_fprintf.c gobuffer strings
ctf_encoder.c ctf_loader.c libctf.c dwarf_loader.c
dutil.c elf_symtab.c rbtree.c)
ctf_encoder.c ctf_loader.c libctf.c btf_encoder.c libbtf.c
dwarf_loader.c dutil.c elf_symtab.c rbtree.c)
add_library(dwarves SHARED ${dwarves_LIB_SRCS})
set_target_properties(dwarves PROPERTIES VERSION 1.0.0 SOVERSION 1)
set_target_properties(dwarves PROPERTIES INTERFACE_LINK_LIBRARIES "")
Expand Down
113 changes: 113 additions & 0 deletions btf.h
@@ -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__ */
174 changes: 174 additions & 0 deletions btf_encoder.c
@@ -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;
}
8 changes: 8 additions & 0 deletions btf_encoder.h
@@ -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_ */

0 comments on commit 94a11b5

Please sign in to comment.