2019-01-18 00:14:24 +01:00
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
2017-10-23 09:24:05 -07:00
/*
* Simple streaming JSON writer
*
* This takes care of the annoying bits of JSON syntax like the commas
* after elements
*
* Authors : Stephen Hemminger < stephen @ networkplumber . org >
*/
# include <stdio.h>
# include <stdbool.h>
# include <stdarg.h>
# include <assert.h>
# include <malloc.h>
# include <inttypes.h>
# include <stdint.h>
2018-12-14 13:56:01 +00:00
# include <linux/compiler.h>
2017-10-23 09:24:05 -07:00
# include "json_writer.h"
struct json_writer {
FILE * out ; /* output file */
unsigned depth ; /* nesting */
bool pretty ; /* optional whitepace */
char sep ; /* either nul or comma */
} ;
/* indentation for pretty print */
static void jsonw_indent ( json_writer_t * self )
{
unsigned i ;
for ( i = 0 ; i < self - > depth ; + + i )
fputs ( " " , self - > out ) ;
}
/* end current line and indent if pretty printing */
static void jsonw_eol ( json_writer_t * self )
{
if ( ! self - > pretty )
return ;
putc ( ' \n ' , self - > out ) ;
jsonw_indent ( self ) ;
}
/* If current object is not empty print a comma */
static void jsonw_eor ( json_writer_t * self )
{
if ( self - > sep ! = ' \0 ' )
putc ( self - > sep , self - > out ) ;
self - > sep = ' , ' ;
}
/* Output JSON encoded string */
/* Handles C escapes, does not do Unicode */
static void jsonw_puts ( json_writer_t * self , const char * str )
{
putc ( ' " ' , self - > out ) ;
for ( ; * str ; + + str )
switch ( * str ) {
case ' \t ' :
fputs ( " \\ t " , self - > out ) ;
break ;
case ' \n ' :
fputs ( " \\ n " , self - > out ) ;
break ;
case ' \r ' :
fputs ( " \\ r " , self - > out ) ;
break ;
case ' \f ' :
fputs ( " \\ f " , self - > out ) ;
break ;
case ' \b ' :
fputs ( " \\ b " , self - > out ) ;
break ;
case ' \\ ' :
fputs ( " \\ n " , self - > out ) ;
break ;
case ' " ' :
fputs ( " \\ \" " , self - > out ) ;
break ;
case ' \' ' :
fputs ( " \\ \' " , self - > out ) ;
break ;
default :
putc ( * str , self - > out ) ;
}
putc ( ' " ' , self - > out ) ;
}
/* Create a new JSON stream */
json_writer_t * jsonw_new ( FILE * f )
{
json_writer_t * self = malloc ( sizeof ( * self ) ) ;
if ( self ) {
self - > out = f ;
self - > depth = 0 ;
self - > pretty = false ;
self - > sep = ' \0 ' ;
}
return self ;
}
/* End output to JSON stream */
void jsonw_destroy ( json_writer_t * * self_p )
{
json_writer_t * self = * self_p ;
assert ( self - > depth = = 0 ) ;
fputs ( " \n " , self - > out ) ;
fflush ( self - > out ) ;
free ( self ) ;
* self_p = NULL ;
}
void jsonw_pretty ( json_writer_t * self , bool on )
{
self - > pretty = on ;
}
/* Basic blocks */
static void jsonw_begin ( json_writer_t * self , int c )
{
jsonw_eor ( self ) ;
putc ( c , self - > out ) ;
+ + self - > depth ;
self - > sep = ' \0 ' ;
}
static void jsonw_end ( json_writer_t * self , int c )
{
assert ( self - > depth > 0 ) ;
- - self - > depth ;
if ( self - > sep ! = ' \0 ' )
jsonw_eol ( self ) ;
putc ( c , self - > out ) ;
self - > sep = ' , ' ;
}
/* Add a JSON property name */
void jsonw_name ( json_writer_t * self , const char * name )
{
jsonw_eor ( self ) ;
jsonw_eol ( self ) ;
self - > sep = ' \0 ' ;
jsonw_puts ( self , name ) ;
putc ( ' : ' , self - > out ) ;
if ( self - > pretty )
putc ( ' ' , self - > out ) ;
}
2018-12-14 13:56:01 +00:00
void __printf ( 2 , 0 )
jsonw_vprintf_enquote ( json_writer_t * self , const char * fmt , va_list ap )
tools: bpftool: add JSON output for `bpftool prog dump xlated *` command
Add a new printing function to dump translated eBPF instructions as
JSON. As for plain output, opcodes are printed only on request (when
`opcodes` is provided on the command line).
The disassembled output is generated by the same code that is used by
the kernel verifier.
Example output:
$ bpftool --json --pretty prog dump xlated id 1
[{
"disasm": "(bf) r6 = r1"
},{
"disasm": "(61) r7 = *(u32 *)(r6 +16)"
},{
"disasm": "(95) exit"
}
]
$ bpftool --json --pretty prog dump xlated id 1 opcodes
[{
"disasm": "(bf) r6 = r1",
"opcodes": {
"code": "0xbf",
"src_reg": "0x1",
"dst_reg": "0x6",
"off": ["0x00","0x00"
],
"imm": ["0x00","0x00","0x00","0x00"
]
}
},{
"disasm": "(61) r7 = *(u32 *)(r6 +16)",
"opcodes": {
"code": "0x61",
"src_reg": "0x6",
"dst_reg": "0x7",
"off": ["0x10","0x00"
],
"imm": ["0x00","0x00","0x00","0x00"
]
}
},{
"disasm": "(95) exit",
"opcodes": {
"code": "0x95",
"src_reg": "0x0",
"dst_reg": "0x0",
"off": ["0x00","0x00"
],
"imm": ["0x00","0x00","0x00","0x00"
]
}
}
]
Signed-off-by: Quentin Monnet <quentin.monnet@netronome.com>
Acked-by: Daniel Borkmann <daniel@iogearbox.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
2017-10-23 09:24:10 -07:00
{
jsonw_eor ( self ) ;
putc ( ' " ' , self - > out ) ;
vfprintf ( self - > out , fmt , ap ) ;
putc ( ' " ' , self - > out ) ;
}
2018-12-14 13:56:01 +00:00
void __printf ( 2 , 3 ) jsonw_printf ( json_writer_t * self , const char * fmt , . . . )
2017-10-23 09:24:05 -07:00
{
va_list ap ;
va_start ( ap , fmt ) ;
jsonw_eor ( self ) ;
vfprintf ( self - > out , fmt , ap ) ;
va_end ( ap ) ;
}
/* Collections */
void jsonw_start_object ( json_writer_t * self )
{
jsonw_begin ( self , ' { ' ) ;
}
void jsonw_end_object ( json_writer_t * self )
{
jsonw_end ( self , ' } ' ) ;
}
void jsonw_start_array ( json_writer_t * self )
{
jsonw_begin ( self , ' [ ' ) ;
}
void jsonw_end_array ( json_writer_t * self )
{
jsonw_end ( self , ' ] ' ) ;
}
/* JSON value types */
void jsonw_string ( json_writer_t * self , const char * value )
{
jsonw_eor ( self ) ;
jsonw_puts ( self , value ) ;
}
void jsonw_bool ( json_writer_t * self , bool val )
{
jsonw_printf ( self , " %s " , val ? " true " : " false " ) ;
}
void jsonw_null ( json_writer_t * self )
{
jsonw_printf ( self , " null " ) ;
}
void jsonw_float_fmt ( json_writer_t * self , const char * fmt , double num )
{
jsonw_printf ( self , fmt , num ) ;
}
# ifdef notused
void jsonw_float ( json_writer_t * self , double num )
{
jsonw_printf ( self , " %g " , num ) ;
}
# endif
void jsonw_hu ( json_writer_t * self , unsigned short num )
{
jsonw_printf ( self , " %hu " , num ) ;
}
void jsonw_uint ( json_writer_t * self , uint64_t num )
{
jsonw_printf ( self , " % " PRIu64 , num ) ;
}
void jsonw_lluint ( json_writer_t * self , unsigned long long int num )
{
jsonw_printf ( self , " %llu " , num ) ;
}
void jsonw_int ( json_writer_t * self , int64_t num )
{
jsonw_printf ( self , " % " PRId64 , num ) ;
}
/* Basic name/value objects */
void jsonw_string_field ( json_writer_t * self , const char * prop , const char * val )
{
jsonw_name ( self , prop ) ;
jsonw_string ( self , val ) ;
}
void jsonw_bool_field ( json_writer_t * self , const char * prop , bool val )
{
jsonw_name ( self , prop ) ;
jsonw_bool ( self , val ) ;
}
# ifdef notused
void jsonw_float_field ( json_writer_t * self , const char * prop , double val )
{
jsonw_name ( self , prop ) ;
jsonw_float ( self , val ) ;
}
# endif
void jsonw_float_field_fmt ( json_writer_t * self ,
const char * prop ,
const char * fmt ,
double val )
{
jsonw_name ( self , prop ) ;
jsonw_float_fmt ( self , fmt , val ) ;
}
void jsonw_uint_field ( json_writer_t * self , const char * prop , uint64_t num )
{
jsonw_name ( self , prop ) ;
jsonw_uint ( self , num ) ;
}
void jsonw_hu_field ( json_writer_t * self , const char * prop , unsigned short num )
{
jsonw_name ( self , prop ) ;
jsonw_hu ( self , num ) ;
}
void jsonw_lluint_field ( json_writer_t * self ,
const char * prop ,
unsigned long long int num )
{
jsonw_name ( self , prop ) ;
jsonw_lluint ( self , num ) ;
}
void jsonw_int_field ( json_writer_t * self , const char * prop , int64_t num )
{
jsonw_name ( self , prop ) ;
jsonw_int ( self , num ) ;
}
void jsonw_null_field ( json_writer_t * self , const char * prop )
{
jsonw_name ( self , prop ) ;
jsonw_null ( self ) ;
}
# ifdef TEST
int main ( int argc , char * * argv )
{
json_writer_t * wr = jsonw_new ( stdout ) ;
jsonw_start_object ( wr ) ;
jsonw_pretty ( wr , true ) ;
jsonw_name ( wr , " Vyatta " ) ;
jsonw_start_object ( wr ) ;
jsonw_string_field ( wr , " url " , " http://vyatta.com " ) ;
jsonw_uint_field ( wr , " downloads " , 2000000ul ) ;
jsonw_float_field ( wr , " stock " , 8.16 ) ;
jsonw_name ( wr , " ARGV " ) ;
jsonw_start_array ( wr ) ;
while ( - - argc )
jsonw_string ( wr , * + + argv ) ;
jsonw_end_array ( wr ) ;
jsonw_name ( wr , " empty " ) ;
jsonw_start_array ( wr ) ;
jsonw_end_array ( wr ) ;
jsonw_name ( wr , " NIL " ) ;
jsonw_start_object ( wr ) ;
jsonw_end_object ( wr ) ;
jsonw_null_field ( wr , " my_null " ) ;
jsonw_name ( wr , " special chars " ) ;
jsonw_start_array ( wr ) ;
jsonw_string_field ( wr , " slash " , " / " ) ;
jsonw_string_field ( wr , " newline " , " \n " ) ;
jsonw_string_field ( wr , " tab " , " \t " ) ;
jsonw_string_field ( wr , " ff " , " \f " ) ;
jsonw_string_field ( wr , " quote " , " \" " ) ;
jsonw_string_field ( wr , " tick " , " \' " ) ;
jsonw_string_field ( wr , " backslash " , " \\ " ) ;
jsonw_end_array ( wr ) ;
jsonw_end_object ( wr ) ;
jsonw_end_object ( wr ) ;
jsonw_destroy ( & wr ) ;
return 0 ;
}
# endif