2020-11-04 20:33:56 -08:00
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2020 Facebook */
# include <stdio.h>
# include <errno.h>
# include <bpf/btf.h>
2020-11-04 20:34:00 -08:00
# include <bpf/libbpf.h>
# include "test_progs.h"
2020-11-04 20:33:56 -08:00
static const char * const btf_kind_str_mapping [ ] = {
[ BTF_KIND_UNKN ] = " UNKNOWN " ,
[ BTF_KIND_INT ] = " INT " ,
[ BTF_KIND_PTR ] = " PTR " ,
[ BTF_KIND_ARRAY ] = " ARRAY " ,
[ BTF_KIND_STRUCT ] = " STRUCT " ,
[ BTF_KIND_UNION ] = " UNION " ,
[ BTF_KIND_ENUM ] = " ENUM " ,
[ BTF_KIND_FWD ] = " FWD " ,
[ BTF_KIND_TYPEDEF ] = " TYPEDEF " ,
[ BTF_KIND_VOLATILE ] = " VOLATILE " ,
[ BTF_KIND_CONST ] = " CONST " ,
[ BTF_KIND_RESTRICT ] = " RESTRICT " ,
[ BTF_KIND_FUNC ] = " FUNC " ,
[ BTF_KIND_FUNC_PROTO ] = " FUNC_PROTO " ,
[ BTF_KIND_VAR ] = " VAR " ,
[ BTF_KIND_DATASEC ] = " DATASEC " ,
2021-02-26 21:22:53 +01:00
[ BTF_KIND_FLOAT ] = " FLOAT " ,
2021-10-12 09:48:38 -07:00
[ BTF_KIND_DECL_TAG ] = " DECL_TAG " ,
2021-11-11 17:26:25 -08:00
[ BTF_KIND_TYPE_TAG ] = " TYPE_TAG " ,
2022-06-06 23:27:03 -07:00
[ BTF_KIND_ENUM64 ] = " ENUM64 " ,
2020-11-04 20:33:56 -08:00
} ;
static const char * btf_kind_str ( __u16 kind )
{
2022-06-06 23:27:03 -07:00
if ( kind > BTF_KIND_ENUM64 )
2020-11-04 20:33:56 -08:00
return " UNKNOWN " ;
return btf_kind_str_mapping [ kind ] ;
}
static const char * btf_int_enc_str ( __u8 encoding )
{
switch ( encoding ) {
case 0 :
return " (none) " ;
case BTF_INT_SIGNED :
return " SIGNED " ;
case BTF_INT_CHAR :
return " CHAR " ;
case BTF_INT_BOOL :
return " BOOL " ;
default :
return " UNKN " ;
}
}
static const char * btf_var_linkage_str ( __u32 linkage )
{
switch ( linkage ) {
case BTF_VAR_STATIC :
return " static " ;
case BTF_VAR_GLOBAL_ALLOCATED :
return " global-alloc " ;
default :
return " (unknown) " ;
}
}
static const char * btf_func_linkage_str ( const struct btf_type * t )
{
switch ( btf_vlen ( t ) ) {
case BTF_FUNC_STATIC :
return " static " ;
case BTF_FUNC_GLOBAL :
return " global " ;
case BTF_FUNC_EXTERN :
return " extern " ;
default :
return " (unknown) " ;
}
}
static const char * btf_str ( const struct btf * btf , __u32 off )
{
if ( ! off )
return " (anon) " ;
return btf__str_by_offset ( btf , off ) ? : " (invalid) " ;
}
int fprintf_btf_type_raw ( FILE * out , const struct btf * btf , __u32 id )
{
const struct btf_type * t ;
int kind , i ;
__u32 vlen ;
t = btf__type_by_id ( btf , id ) ;
if ( ! t )
return - EINVAL ;
vlen = btf_vlen ( t ) ;
kind = btf_kind ( t ) ;
fprintf ( out , " [%u] %s '%s' " , id , btf_kind_str ( kind ) , btf_str ( btf , t - > name_off ) ) ;
switch ( kind ) {
case BTF_KIND_INT :
fprintf ( out , " size=%u bits_offset=%u nr_bits=%u encoding=%s " ,
t - > size , btf_int_offset ( t ) , btf_int_bits ( t ) ,
btf_int_enc_str ( btf_int_encoding ( t ) ) ) ;
break ;
case BTF_KIND_PTR :
case BTF_KIND_CONST :
case BTF_KIND_VOLATILE :
case BTF_KIND_RESTRICT :
case BTF_KIND_TYPEDEF :
2021-11-11 17:26:25 -08:00
case BTF_KIND_TYPE_TAG :
2020-11-04 20:33:56 -08:00
fprintf ( out , " type_id=%u " , t - > type ) ;
break ;
case BTF_KIND_ARRAY : {
const struct btf_array * arr = btf_array ( t ) ;
fprintf ( out , " type_id=%u index_type_id=%u nr_elems=%u " ,
arr - > type , arr - > index_type , arr - > nelems ) ;
break ;
}
case BTF_KIND_STRUCT :
case BTF_KIND_UNION : {
const struct btf_member * m = btf_members ( t ) ;
fprintf ( out , " size=%u vlen=%u " , t - > size , vlen ) ;
for ( i = 0 ; i < vlen ; i + + , m + + ) {
__u32 bit_off , bit_sz ;
bit_off = btf_member_bit_offset ( t , i ) ;
bit_sz = btf_member_bitfield_size ( t , i ) ;
fprintf ( out , " \n \t '%s' type_id=%u bits_offset=%u " ,
btf_str ( btf , m - > name_off ) , m - > type , bit_off ) ;
if ( bit_sz )
fprintf ( out , " bitfield_size=%u " , bit_sz ) ;
}
break ;
}
case BTF_KIND_ENUM : {
const struct btf_enum * v = btf_enum ( t ) ;
2022-06-06 23:27:03 -07:00
const char * fmt_str ;
2020-11-04 20:33:56 -08:00
2022-06-06 23:27:03 -07:00
fmt_str = btf_kflag ( t ) ? " \n \t '%s' val=%d " : " \n \t '%s' val=%u " ;
fprintf ( out , " encoding=%s size=%u vlen=%u " ,
btf_kflag ( t ) ? " SIGNED " : " UNSIGNED " , t - > size , vlen ) ;
2020-11-04 20:33:56 -08:00
for ( i = 0 ; i < vlen ; i + + , v + + ) {
2022-06-06 23:27:03 -07:00
fprintf ( out , fmt_str ,
2020-11-04 20:33:56 -08:00
btf_str ( btf , v - > name_off ) , v - > val ) ;
}
break ;
}
2022-06-06 23:27:03 -07:00
case BTF_KIND_ENUM64 : {
const struct btf_enum64 * v = btf_enum64 ( t ) ;
const char * fmt_str ;
fmt_str = btf_kflag ( t ) ? " \n \t '%s' val=%lld " : " \n \t '%s' val=%llu " ;
fprintf ( out , " encoding=%s size=%u vlen=%u " ,
btf_kflag ( t ) ? " SIGNED " : " UNSIGNED " , t - > size , vlen ) ;
for ( i = 0 ; i < vlen ; i + + , v + + ) {
fprintf ( out , fmt_str ,
btf_str ( btf , v - > name_off ) ,
( ( __u64 ) v - > val_hi32 < < 32 ) | v - > val_lo32 ) ;
}
break ;
}
2020-11-04 20:33:56 -08:00
case BTF_KIND_FWD :
fprintf ( out , " fwd_kind=%s " , btf_kflag ( t ) ? " union " : " struct " ) ;
break ;
case BTF_KIND_FUNC :
fprintf ( out , " type_id=%u linkage=%s " , t - > type , btf_func_linkage_str ( t ) ) ;
break ;
case BTF_KIND_FUNC_PROTO : {
const struct btf_param * p = btf_params ( t ) ;
fprintf ( out , " ret_type_id=%u vlen=%u " , t - > type , vlen ) ;
for ( i = 0 ; i < vlen ; i + + , p + + ) {
fprintf ( out , " \n \t '%s' type_id=%u " ,
btf_str ( btf , p - > name_off ) , p - > type ) ;
}
break ;
}
case BTF_KIND_VAR :
fprintf ( out , " type_id=%u, linkage=%s " ,
t - > type , btf_var_linkage_str ( btf_var ( t ) - > linkage ) ) ;
break ;
case BTF_KIND_DATASEC : {
const struct btf_var_secinfo * v = btf_var_secinfos ( t ) ;
fprintf ( out , " size=%u vlen=%u " , t - > size , vlen ) ;
for ( i = 0 ; i < vlen ; i + + , v + + ) {
fprintf ( out , " \n \t type_id=%u offset=%u size=%u " ,
v - > type , v - > offset , v - > size ) ;
}
break ;
}
2021-02-26 21:22:53 +01:00
case BTF_KIND_FLOAT :
fprintf ( out , " size=%u " , t - > size ) ;
break ;
2021-10-12 09:48:38 -07:00
case BTF_KIND_DECL_TAG :
2021-09-14 15:30:36 -07:00
fprintf ( out , " type_id=%u component_idx=%d " ,
2021-10-12 09:48:38 -07:00
t - > type , btf_decl_tag ( t ) - > component_idx ) ;
2021-09-14 15:30:36 -07:00
break ;
2020-11-04 20:33:56 -08:00
default :
break ;
}
return 0 ;
}
/* Print raw BTF type dump into a local buffer and return string pointer back.
* Buffer * will * be overwritten by subsequent btf_type_raw_dump ( ) calls
*/
const char * btf_type_raw_dump ( const struct btf * btf , int type_id )
{
static char buf [ 16 * 1024 ] ;
FILE * buf_file ;
buf_file = fmemopen ( buf , sizeof ( buf ) - 1 , " w " ) ;
if ( ! buf_file ) {
fprintf ( stderr , " Failed to open memstream: %d \n " , errno ) ;
return NULL ;
}
fprintf_btf_type_raw ( buf_file , btf , type_id ) ;
fflush ( buf_file ) ;
fclose ( buf_file ) ;
return buf ;
}
2020-11-04 20:34:00 -08:00
int btf_validate_raw ( struct btf * btf , int nr_types , const char * exp_types [ ] )
{
int i ;
bool ok = true ;
2021-10-22 21:06:23 +08:00
ASSERT_EQ ( btf__type_cnt ( btf ) - 1 , nr_types , " btf_nr_types " ) ;
2020-11-04 20:34:00 -08:00
for ( i = 1 ; i < = nr_types ; i + + ) {
if ( ! ASSERT_STREQ ( btf_type_raw_dump ( btf , i ) , exp_types [ i - 1 ] , " raw_dump " ) )
ok = false ;
}
return ok ;
}
static void btf_dump_printf ( void * ctx , const char * fmt , va_list args )
{
vfprintf ( ctx , fmt , args ) ;
}
/* Print BTF-to-C dump into a local buffer and return string pointer back.
* Buffer * will * be overwritten by subsequent btf_type_raw_dump ( ) calls
*/
const char * btf_type_c_dump ( const struct btf * btf )
{
static char buf [ 16 * 1024 ] ;
FILE * buf_file ;
struct btf_dump * d = NULL ;
int err , i ;
buf_file = fmemopen ( buf , sizeof ( buf ) - 1 , " w " ) ;
if ( ! buf_file ) {
fprintf ( stderr , " Failed to open memstream: %d \n " , errno ) ;
return NULL ;
}
2021-11-10 21:36:22 -08:00
d = btf_dump__new ( btf , btf_dump_printf , buf_file , NULL ) ;
2020-11-04 20:34:00 -08:00
if ( libbpf_get_error ( d ) ) {
fprintf ( stderr , " Failed to create btf_dump instance: %ld \n " , libbpf_get_error ( d ) ) ;
2021-11-07 08:55:15 -08:00
goto err_out ;
2020-11-04 20:34:00 -08:00
}
2021-10-22 21:06:23 +08:00
for ( i = 1 ; i < btf__type_cnt ( btf ) ; i + + ) {
2020-11-04 20:34:00 -08:00
err = btf_dump__dump_type ( d , i ) ;
if ( err ) {
fprintf ( stderr , " Failed to dump type [%d]: %d \n " , i , err ) ;
2021-11-07 08:55:15 -08:00
goto err_out ;
2020-11-04 20:34:00 -08:00
}
}
2021-11-07 08:55:15 -08:00
btf_dump__free ( d ) ;
2020-11-04 20:34:00 -08:00
fflush ( buf_file ) ;
fclose ( buf_file ) ;
return buf ;
2021-11-07 08:55:15 -08:00
err_out :
btf_dump__free ( d ) ;
fclose ( buf_file ) ;
return NULL ;
2020-11-04 20:34:00 -08:00
}