@@ -1272,6 +1272,139 @@ static void test_stacktrace_build_id(void)
1272
1272
return ;
1273
1273
}
1274
1274
1275
+ static void test_stacktrace_build_id_nmi (void )
1276
+ {
1277
+ int control_map_fd , stackid_hmap_fd , stackmap_fd , stack_amap_fd ;
1278
+ const char * file = "./test_stacktrace_build_id.o" ;
1279
+ int err , pmu_fd , prog_fd ;
1280
+ struct perf_event_attr attr = {
1281
+ .sample_freq = 5000 ,
1282
+ .freq = 1 ,
1283
+ .type = PERF_TYPE_HARDWARE ,
1284
+ .config = PERF_COUNT_HW_CPU_CYCLES ,
1285
+ };
1286
+ __u32 key , previous_key , val , duration = 0 ;
1287
+ struct bpf_object * obj ;
1288
+ char buf [256 ];
1289
+ int i , j ;
1290
+ struct bpf_stack_build_id id_offs [PERF_MAX_STACK_DEPTH ];
1291
+ int build_id_matches = 0 ;
1292
+
1293
+ err = bpf_prog_load (file , BPF_PROG_TYPE_PERF_EVENT , & obj , & prog_fd );
1294
+ if (CHECK (err , "prog_load" , "err %d errno %d\n" , err , errno ))
1295
+ return ;
1296
+
1297
+ pmu_fd = syscall (__NR_perf_event_open , & attr , -1 /* pid */ ,
1298
+ 0 /* cpu 0 */ , -1 /* group id */ ,
1299
+ 0 /* flags */ );
1300
+ if (CHECK (pmu_fd < 0 , "perf_event_open" ,
1301
+ "err %d errno %d. Does the test host support PERF_COUNT_HW_CPU_CYCLES?\n" ,
1302
+ pmu_fd , errno ))
1303
+ goto close_prog ;
1304
+
1305
+ err = ioctl (pmu_fd , PERF_EVENT_IOC_ENABLE , 0 );
1306
+ if (CHECK (err , "perf_event_ioc_enable" , "err %d errno %d\n" ,
1307
+ err , errno ))
1308
+ goto close_pmu ;
1309
+
1310
+ err = ioctl (pmu_fd , PERF_EVENT_IOC_SET_BPF , prog_fd );
1311
+ if (CHECK (err , "perf_event_ioc_set_bpf" , "err %d errno %d\n" ,
1312
+ err , errno ))
1313
+ goto disable_pmu ;
1314
+
1315
+ /* find map fds */
1316
+ control_map_fd = bpf_find_map (__func__ , obj , "control_map" );
1317
+ if (CHECK (control_map_fd < 0 , "bpf_find_map control_map" ,
1318
+ "err %d errno %d\n" , err , errno ))
1319
+ goto disable_pmu ;
1320
+
1321
+ stackid_hmap_fd = bpf_find_map (__func__ , obj , "stackid_hmap" );
1322
+ if (CHECK (stackid_hmap_fd < 0 , "bpf_find_map stackid_hmap" ,
1323
+ "err %d errno %d\n" , err , errno ))
1324
+ goto disable_pmu ;
1325
+
1326
+ stackmap_fd = bpf_find_map (__func__ , obj , "stackmap" );
1327
+ if (CHECK (stackmap_fd < 0 , "bpf_find_map stackmap" , "err %d errno %d\n" ,
1328
+ err , errno ))
1329
+ goto disable_pmu ;
1330
+
1331
+ stack_amap_fd = bpf_find_map (__func__ , obj , "stack_amap" );
1332
+ if (CHECK (stack_amap_fd < 0 , "bpf_find_map stack_amap" ,
1333
+ "err %d errno %d\n" , err , errno ))
1334
+ goto disable_pmu ;
1335
+
1336
+ assert (system ("dd if=/dev/urandom of=/dev/zero count=4 2> /dev/null" )
1337
+ == 0 );
1338
+ assert (system ("taskset 0x1 ./urandom_read 100000" ) == 0 );
1339
+ /* disable stack trace collection */
1340
+ key = 0 ;
1341
+ val = 1 ;
1342
+ bpf_map_update_elem (control_map_fd , & key , & val , 0 );
1343
+
1344
+ /* for every element in stackid_hmap, we can find a corresponding one
1345
+ * in stackmap, and vise versa.
1346
+ */
1347
+ err = compare_map_keys (stackid_hmap_fd , stackmap_fd );
1348
+ if (CHECK (err , "compare_map_keys stackid_hmap vs. stackmap" ,
1349
+ "err %d errno %d\n" , err , errno ))
1350
+ goto disable_pmu ;
1351
+
1352
+ err = compare_map_keys (stackmap_fd , stackid_hmap_fd );
1353
+ if (CHECK (err , "compare_map_keys stackmap vs. stackid_hmap" ,
1354
+ "err %d errno %d\n" , err , errno ))
1355
+ goto disable_pmu ;
1356
+
1357
+ err = extract_build_id (buf , 256 );
1358
+
1359
+ if (CHECK (err , "get build_id with readelf" ,
1360
+ "err %d errno %d\n" , err , errno ))
1361
+ goto disable_pmu ;
1362
+
1363
+ err = bpf_map_get_next_key (stackmap_fd , NULL , & key );
1364
+ if (CHECK (err , "get_next_key from stackmap" ,
1365
+ "err %d, errno %d\n" , err , errno ))
1366
+ goto disable_pmu ;
1367
+
1368
+ do {
1369
+ char build_id [64 ];
1370
+
1371
+ err = bpf_map_lookup_elem (stackmap_fd , & key , id_offs );
1372
+ if (CHECK (err , "lookup_elem from stackmap" ,
1373
+ "err %d, errno %d\n" , err , errno ))
1374
+ goto disable_pmu ;
1375
+ for (i = 0 ; i < PERF_MAX_STACK_DEPTH ; ++ i )
1376
+ if (id_offs [i ].status == BPF_STACK_BUILD_ID_VALID &&
1377
+ id_offs [i ].offset != 0 ) {
1378
+ for (j = 0 ; j < 20 ; ++ j )
1379
+ sprintf (build_id + 2 * j , "%02x" ,
1380
+ id_offs [i ].build_id [j ] & 0xff );
1381
+ if (strstr (buf , build_id ) != NULL )
1382
+ build_id_matches = 1 ;
1383
+ }
1384
+ previous_key = key ;
1385
+ } while (bpf_map_get_next_key (stackmap_fd , & previous_key , & key ) == 0 );
1386
+
1387
+ if (CHECK (build_id_matches < 1 , "build id match" ,
1388
+ "Didn't find expected build ID from the map\n" ))
1389
+ goto disable_pmu ;
1390
+
1391
+ /*
1392
+ * We intentionally skip compare_stack_ips(). This is because we
1393
+ * only support one in_nmi() ips-to-build_id translation per cpu
1394
+ * at any time, thus stack_amap here will always fallback to
1395
+ * BPF_STACK_BUILD_ID_IP;
1396
+ */
1397
+
1398
+ disable_pmu :
1399
+ ioctl (pmu_fd , PERF_EVENT_IOC_DISABLE );
1400
+
1401
+ close_pmu :
1402
+ close (pmu_fd );
1403
+
1404
+ close_prog :
1405
+ bpf_object__close (obj );
1406
+ }
1407
+
1275
1408
#define MAX_CNT_RAWTP 10ull
1276
1409
#define MAX_STACK_RAWTP 100
1277
1410
struct get_stack_trace_t {
@@ -1425,6 +1558,7 @@ int main(void)
1425
1558
test_tp_attach_query ();
1426
1559
test_stacktrace_map ();
1427
1560
test_stacktrace_build_id ();
1561
+ test_stacktrace_build_id_nmi ();
1428
1562
test_stacktrace_map_raw_tp ();
1429
1563
test_get_stack_raw_tp ();
1430
1564
0 commit comments