3
3
#define _GNU_SOURCE
4
4
#include <argp.h>
5
5
#include <libgen.h>
6
+ #include <ctype.h>
6
7
#include <string.h>
7
8
#include <stdlib.h>
8
9
#include <sched.h>
@@ -154,6 +155,16 @@ struct filter {
154
155
bool abs ;
155
156
};
156
157
158
+ struct var_preset {
159
+ char * name ;
160
+ enum { INTEGRAL , ENUMERATOR } type ;
161
+ union {
162
+ long long ivalue ;
163
+ char * svalue ;
164
+ };
165
+ bool applied ;
166
+ };
167
+
157
168
static struct env {
158
169
char * * filenames ;
159
170
int filename_cnt ;
@@ -195,6 +206,8 @@ static struct env {
195
206
int progs_processed ;
196
207
int progs_skipped ;
197
208
int top_src_lines ;
209
+ struct var_preset * presets ;
210
+ int npresets ;
198
211
} env ;
199
212
200
213
static int libbpf_print_fn (enum libbpf_print_level level , const char * format , va_list args )
@@ -246,12 +259,15 @@ static const struct argp_option opts[] = {
246
259
{ "test-reg-invariants" , 'r' , NULL , 0 ,
247
260
"Force BPF verifier failure on register invariant violation (BPF_F_TEST_REG_INVARIANTS program flag)" },
248
261
{ "top-src-lines" , 'S' , "N" , 0 , "Emit N most frequent source code lines" },
262
+ { "set-global-vars" , 'G' , "GLOBAL" , 0 , "Set global variables provided in the expression, for example \"var1 = 1\"" },
249
263
{},
250
264
};
251
265
252
266
static int parse_stats (const char * stats_str , struct stat_specs * specs );
253
267
static int append_filter (struct filter * * filters , int * cnt , const char * str );
254
268
static int append_filter_file (const char * path );
269
+ static int append_var_preset (struct var_preset * * presets , int * cnt , const char * expr );
270
+ static int append_var_preset_file (const char * filename );
255
271
256
272
static error_t parse_arg (int key , char * arg , struct argp_state * state )
257
273
{
@@ -353,6 +369,17 @@ static error_t parse_arg(int key, char *arg, struct argp_state *state)
353
369
argp_usage (state );
354
370
}
355
371
break ;
372
+ case 'G' : {
373
+ if (arg [0 ] == '@' )
374
+ err = append_var_preset_file (arg + 1 );
375
+ else
376
+ err = append_var_preset (& env .presets , & env .npresets , arg );
377
+ if (err ) {
378
+ fprintf (stderr , "Failed to parse global variable presets: %s\n" , arg );
379
+ return err ;
380
+ }
381
+ break ;
382
+ }
356
383
case ARGP_KEY_ARG :
357
384
tmp = realloc (env .filenames , (env .filename_cnt + 1 ) * sizeof (* env .filenames ));
358
385
if (!tmp )
@@ -632,7 +659,7 @@ static int append_filter_file(const char *path)
632
659
f = fopen (path , "r" );
633
660
if (!f ) {
634
661
err = - errno ;
635
- fprintf (stderr , "Failed to open filters in '%s': %d \n" , path , err );
662
+ fprintf (stderr , "Failed to open filters in '%s': %s \n" , path , strerror ( err ) );
636
663
return err ;
637
664
}
638
665
@@ -1292,6 +1319,261 @@ static int process_prog(const char *filename, struct bpf_object *obj, struct bpf
1292
1319
return 0 ;
1293
1320
};
1294
1321
1322
+ static int append_var_preset (struct var_preset * * presets , int * cnt , const char * expr )
1323
+ {
1324
+ void * tmp ;
1325
+ struct var_preset * cur ;
1326
+ char var [256 ], val [256 ], * val_end ;
1327
+ long long value ;
1328
+ int n ;
1329
+
1330
+ tmp = realloc (* presets , (* cnt + 1 ) * sizeof (* * presets ));
1331
+ if (!tmp )
1332
+ return - ENOMEM ;
1333
+ * presets = tmp ;
1334
+ cur = & (* presets )[* cnt ];
1335
+ memset (cur , 0 , sizeof (* cur ));
1336
+ (* cnt )++ ;
1337
+
1338
+ if (sscanf (expr , "%s = %s %n" , var , val , & n ) != 2 || n != strlen (expr )) {
1339
+ fprintf (stderr , "Failed to parse expression '%s'\n" , expr );
1340
+ return - EINVAL ;
1341
+ }
1342
+
1343
+ if (val [0 ] == '-' || isdigit (val [0 ])) {
1344
+ /* must be a number */
1345
+ errno = 0 ;
1346
+ value = strtoll (val , & val_end , 0 );
1347
+ if (errno == ERANGE ) {
1348
+ errno = 0 ;
1349
+ value = strtoull (val , & val_end , 0 );
1350
+ }
1351
+ if (errno || * val_end != '\0' ) {
1352
+ fprintf (stderr , "Failed to parse value '%s'\n" , val );
1353
+ return - EINVAL ;
1354
+ }
1355
+ cur -> ivalue = value ;
1356
+ cur -> type = INTEGRAL ;
1357
+ } else {
1358
+ /* if not a number, consider it enum value */
1359
+ cur -> svalue = strdup (val );
1360
+ if (!cur -> svalue )
1361
+ return - ENOMEM ;
1362
+ cur -> type = ENUMERATOR ;
1363
+ }
1364
+
1365
+ cur -> name = strdup (var );
1366
+ if (!cur -> name )
1367
+ return - ENOMEM ;
1368
+
1369
+ return 0 ;
1370
+ }
1371
+
1372
+ static int append_var_preset_file (const char * filename )
1373
+ {
1374
+ char buf [1024 ];
1375
+ FILE * f ;
1376
+ int err = 0 ;
1377
+
1378
+ f = fopen (filename , "rt" );
1379
+ if (!f ) {
1380
+ err = - errno ;
1381
+ fprintf (stderr , "Failed to open presets in '%s': %s\n" , filename , strerror (err ));
1382
+ return - EINVAL ;
1383
+ }
1384
+
1385
+ while (fscanf (f , " %1023[^\n]\n" , buf ) == 1 ) {
1386
+ if (buf [0 ] == '\0' || buf [0 ] == '#' )
1387
+ continue ;
1388
+
1389
+ err = append_var_preset (& env .presets , & env .npresets , buf );
1390
+ if (err )
1391
+ goto cleanup ;
1392
+ }
1393
+
1394
+ cleanup :
1395
+ fclose (f );
1396
+ return err ;
1397
+ }
1398
+
1399
+ static bool is_signed_type (const struct btf_type * t )
1400
+ {
1401
+ if (btf_is_int (t ))
1402
+ return btf_int_encoding (t ) & BTF_INT_SIGNED ;
1403
+ if (btf_is_any_enum (t ))
1404
+ return btf_kflag (t );
1405
+ return true;
1406
+ }
1407
+
1408
+ static int enum_value_from_name (const struct btf * btf , const struct btf_type * t ,
1409
+ const char * evalue , long long * retval )
1410
+ {
1411
+ if (btf_is_enum (t )) {
1412
+ struct btf_enum * e = btf_enum (t );
1413
+ int i , n = btf_vlen (t );
1414
+
1415
+ for (i = 0 ; i < n ; ++ i , ++ e ) {
1416
+ const char * cur_name = btf__name_by_offset (btf , e -> name_off );
1417
+
1418
+ if (strcmp (cur_name , evalue ) == 0 ) {
1419
+ * retval = e -> val ;
1420
+ return 0 ;
1421
+ }
1422
+ }
1423
+ } else if (btf_is_enum64 (t )) {
1424
+ struct btf_enum64 * e = btf_enum64 (t );
1425
+ int i , n = btf_vlen (t );
1426
+
1427
+ for (i = 0 ; i < n ; ++ i , ++ e ) {
1428
+ const char * cur_name = btf__name_by_offset (btf , e -> name_off );
1429
+ __u64 value = btf_enum64_value (e );
1430
+
1431
+ if (strcmp (cur_name , evalue ) == 0 ) {
1432
+ * retval = value ;
1433
+ return 0 ;
1434
+ }
1435
+ }
1436
+ }
1437
+ return - EINVAL ;
1438
+ }
1439
+
1440
+ static bool is_preset_supported (const struct btf_type * t )
1441
+ {
1442
+ return btf_is_int (t ) || btf_is_enum (t ) || btf_is_enum64 (t );
1443
+ }
1444
+
1445
+ static int set_global_var (struct bpf_object * obj , struct btf * btf , const struct btf_type * t ,
1446
+ struct bpf_map * map , struct btf_var_secinfo * sinfo ,
1447
+ struct var_preset * preset )
1448
+ {
1449
+ const struct btf_type * base_type ;
1450
+ void * ptr ;
1451
+ long long value = preset -> ivalue ;
1452
+ size_t size ;
1453
+
1454
+ base_type = btf__type_by_id (btf , btf__resolve_type (btf , t -> type ));
1455
+ if (!base_type ) {
1456
+ fprintf (stderr , "Failed to resolve type %d\n" , t -> type );
1457
+ return - EINVAL ;
1458
+ }
1459
+ if (!is_preset_supported (base_type )) {
1460
+ fprintf (stderr , "Setting value for type %s is not supported\n" ,
1461
+ btf__name_by_offset (btf , base_type -> name_off ));
1462
+ return - EINVAL ;
1463
+ }
1464
+
1465
+ if (preset -> type == ENUMERATOR ) {
1466
+ if (btf_is_any_enum (base_type )) {
1467
+ if (enum_value_from_name (btf , base_type , preset -> svalue , & value )) {
1468
+ fprintf (stderr ,
1469
+ "Failed to find integer value for enum element %s\n" ,
1470
+ preset -> svalue );
1471
+ return - EINVAL ;
1472
+ }
1473
+ } else {
1474
+ fprintf (stderr , "Value %s is not supported for type %s\n" ,
1475
+ preset -> svalue , btf__name_by_offset (btf , base_type -> name_off ));
1476
+ return - EINVAL ;
1477
+ }
1478
+ }
1479
+
1480
+ /* Check if value fits into the target variable size */
1481
+ if (sinfo -> size < sizeof (value )) {
1482
+ bool is_signed = is_signed_type (base_type );
1483
+ __u32 unsigned_bits = sinfo -> size * 8 - (is_signed ? 1 : 0 );
1484
+ long long max_val = 1ll << unsigned_bits ;
1485
+
1486
+ if (value >= max_val || value < - max_val ) {
1487
+ fprintf (stderr ,
1488
+ "Variable %s value %lld is out of range [%lld; %lld]\n" ,
1489
+ btf__name_by_offset (btf , t -> name_off ), value ,
1490
+ is_signed ? - max_val : 0 , max_val - 1 );
1491
+ return - EINVAL ;
1492
+ }
1493
+ }
1494
+
1495
+ ptr = bpf_map__initial_value (map , & size );
1496
+ if (!ptr || sinfo -> offset + sinfo -> size > size )
1497
+ return - EINVAL ;
1498
+
1499
+ if (__BYTE_ORDER == __LITTLE_ENDIAN ) {
1500
+ memcpy (ptr + sinfo -> offset , & value , sinfo -> size );
1501
+ } else { /* __BYTE_ORDER == __BIG_ENDIAN */
1502
+ __u8 src_offset = sizeof (value ) - sinfo -> size ;
1503
+
1504
+ memcpy (ptr + sinfo -> offset , (void * )& value + src_offset , sinfo -> size );
1505
+ }
1506
+ return 0 ;
1507
+ }
1508
+
1509
+ static int set_global_vars (struct bpf_object * obj , struct var_preset * presets , int npresets )
1510
+ {
1511
+ struct btf_var_secinfo * sinfo ;
1512
+ const char * sec_name ;
1513
+ const struct btf_type * t ;
1514
+ struct bpf_map * map ;
1515
+ struct btf * btf ;
1516
+ int i , j , k , n , cnt , err = 0 ;
1517
+
1518
+ if (npresets == 0 )
1519
+ return 0 ;
1520
+
1521
+ btf = bpf_object__btf (obj );
1522
+ if (!btf )
1523
+ return - EINVAL ;
1524
+
1525
+ cnt = btf__type_cnt (btf );
1526
+ for (i = 1 ; i != cnt ; ++ i ) {
1527
+ t = btf__type_by_id (btf , i );
1528
+
1529
+ if (!btf_is_datasec (t ))
1530
+ continue ;
1531
+
1532
+ sinfo = btf_var_secinfos (t );
1533
+ sec_name = btf__name_by_offset (btf , t -> name_off );
1534
+ map = bpf_object__find_map_by_name (obj , sec_name );
1535
+ if (!map )
1536
+ continue ;
1537
+
1538
+ n = btf_vlen (t );
1539
+ for (j = 0 ; j < n ; ++ j , ++ sinfo ) {
1540
+ const struct btf_type * var_type = btf__type_by_id (btf , sinfo -> type );
1541
+ const char * var_name ;
1542
+
1543
+ if (!btf_is_var (var_type ))
1544
+ continue ;
1545
+
1546
+ var_name = btf__name_by_offset (btf , var_type -> name_off );
1547
+
1548
+ for (k = 0 ; k < npresets ; ++ k ) {
1549
+ if (strcmp (var_name , presets [k ].name ) != 0 )
1550
+ continue ;
1551
+
1552
+ if (presets [k ].applied ) {
1553
+ fprintf (stderr , "Variable %s is set more than once" ,
1554
+ var_name );
1555
+ return - EINVAL ;
1556
+ }
1557
+
1558
+ err = set_global_var (obj , btf , var_type , map , sinfo , presets + k );
1559
+ if (err )
1560
+ return err ;
1561
+
1562
+ presets [k ].applied = true;
1563
+ break ;
1564
+ }
1565
+ }
1566
+ }
1567
+ for (i = 0 ; i < npresets ; ++ i ) {
1568
+ if (!presets [i ].applied ) {
1569
+ fprintf (stderr , "Global variable preset %s has not been applied\n" ,
1570
+ presets [i ].name );
1571
+ }
1572
+ presets [i ].applied = false;
1573
+ }
1574
+ return err ;
1575
+ }
1576
+
1295
1577
static int process_obj (const char * filename )
1296
1578
{
1297
1579
const char * base_filename = basename (strdupa (filename ));
@@ -1341,6 +1623,11 @@ static int process_obj(const char *filename)
1341
1623
if (prog_cnt == 1 ) {
1342
1624
prog = bpf_object__next_program (obj , NULL );
1343
1625
bpf_program__set_autoload (prog , true);
1626
+ err = set_global_vars (obj , env .presets , env .npresets );
1627
+ if (err ) {
1628
+ fprintf (stderr , "Failed to set global variables %d\n" , err );
1629
+ goto cleanup ;
1630
+ }
1344
1631
process_prog (filename , obj , prog );
1345
1632
goto cleanup ;
1346
1633
}
@@ -1355,6 +1642,12 @@ static int process_obj(const char *filename)
1355
1642
goto cleanup ;
1356
1643
}
1357
1644
1645
+ err = set_global_vars (tobj , env .presets , env .npresets );
1646
+ if (err ) {
1647
+ fprintf (stderr , "Failed to set global variables %d\n" , err );
1648
+ goto cleanup ;
1649
+ }
1650
+
1358
1651
lprog = NULL ;
1359
1652
bpf_object__for_each_program (tprog , tobj ) {
1360
1653
const char * tprog_name = bpf_program__name (tprog );
@@ -2460,5 +2753,11 @@ int main(int argc, char **argv)
2460
2753
free (env .deny_filters [i ].prog_glob );
2461
2754
}
2462
2755
free (env .deny_filters );
2756
+ for (i = 0 ; i < env .npresets ; ++ i ) {
2757
+ free (env .presets [i ].name );
2758
+ if (env .presets [i ].type == ENUMERATOR )
2759
+ free (env .presets [i ].svalue );
2760
+ }
2761
+ free (env .presets );
2463
2762
return - err ;
2464
2763
}
0 commit comments