@@ -528,18 +528,29 @@ let function_name = ref ""
528
528
let tailrec_entry_point = ref None
529
529
530
530
(* Emit tracing probes *)
531
+ type probe_handler =
532
+ {
533
+ probe_stack_offset: int;
534
+ probe_num_stack_slots: int array;
535
+ (* Record frame info held in the corresponding mutable variables. *)
536
+ probe_handler_code_sym: string;
537
+ (* Probe handler function symbol. *)
538
+ probe_arg: Reg.t array;
539
+ probe_live: Reg.Set.t;
540
+ (* Information about Iprobe instruction,
541
+ recorded at probe site and used for emitting the notes and
542
+ the wrapper code at the end of the compilation unit. *)
543
+ }
531
544
532
545
type probe =
533
546
{
534
- stack_offset: int;
535
- num_stack_slots: int array;
536
- (* Record frame info held in the corresponding mutable variables. *)
537
547
probe_label: label;
538
548
(* Probe site, recorded in .note.stapsdt section
539
549
for enabling and disabling the probes *)
540
- probe_insn: Linear.instruction;
541
- (* Iprobe instruction, recorded at probe site and used for emitting
542
- the notes and the wrapper code at the end of the compilation unit. *)
550
+ probe_name: string;
551
+ (* User-defined name of the probe. *)
552
+ probe_handler: probe_handler option;
553
+ (* User-defined handler or None for dummy probes. *)
543
554
}
544
555
545
556
let probe_handler_wrapper_name probe_label =
@@ -935,13 +946,20 @@ let emit_instr fallthrough i =
935
946
in
936
947
I.prefetch is_write locality (addressing addr QWORD i 0)
937
948
| Lop (Iname_for_debugger _) -> ()
938
- | Lop (Iprobe _ ) ->
949
+ | Lop (Iprobe { name; handler_code_sym } ) ->
939
950
let probe_label = new_label () in
951
+ let h =
952
+ { probe_handler_code_sym = handler_code_sym;
953
+ probe_arg = Array.copy i.arg;
954
+ probe_live = i.live;
955
+ probe_stack_offset = !stack_offset;
956
+ probe_num_stack_slots = Array.copy num_stack_slots;
957
+ }
958
+ in
940
959
let probe =
941
960
{ probe_label;
942
- probe_insn = i;
943
- stack_offset = !stack_offset;
944
- num_stack_slots = Array.copy num_stack_slots;
961
+ probe_name = name;
962
+ probe_handler = Some h;
945
963
}
946
964
in
947
965
probes := probe :: !probes;
@@ -1283,23 +1301,20 @@ let make_stack_loc ~offset i (r : Reg.t) =
1283
1301
1284
1302
let emit_probe_handler_wrapper p =
1285
1303
let wrap_label = probe_handler_wrapper_name p.probe_label in
1286
- let probe_name, handler_code_sym =
1287
- match p.probe_insn.desc with
1288
- | Lop (Iprobe { name; handler_code_sym; }) -> name, handler_code_sym
1289
- | _ -> assert false
1290
- in
1304
+ let h = Option.get p.probe_handler in
1291
1305
(* Restore stack frame info as it was at the probe site, so we can easily
1292
1306
refer to slots in the corresponding frame. (As per the comment above,
1293
1307
recall that the wrapper does however have its own frame.) *)
1294
1308
frame_required := true;
1295
- stack_offset := p.stack_offset ;
1309
+ stack_offset := h.probe_stack_offset ;
1296
1310
for i = 0 to Proc.num_register_classes - 1 do
1297
- num_stack_slots.(i) <- p.num_stack_slots .(i);
1311
+ num_stack_slots.(i) <- h.probe_num_stack_slots .(i);
1298
1312
done;
1299
1313
(* Account for the return address that is now pushed on the stack. *)
1300
1314
stack_offset := !stack_offset + 8;
1301
1315
(* Emit function entry code *)
1302
- D.comment (Printf.sprintf "probe %s %s" probe_name handler_code_sym);
1316
+ D.comment (Printf.sprintf "probe %s %s" p.probe_name
1317
+ h.probe_handler_code_sym);
1303
1318
emit_named_text_section wrap_label;
1304
1319
D.align 16;
1305
1320
_label wrap_label;
@@ -1313,15 +1328,15 @@ let emit_probe_handler_wrapper p =
1313
1328
assert (size_addr = 8 && size_int = 8 && size_float = 8);
1314
1329
(* Compute the size of stack slots for all live hard registers. *)
1315
1330
let live =
1316
- Reg.Set.elements p.probe_insn.live
1331
+ Reg.Set.elements h.probe_live
1317
1332
|> List.filter Reg.is_reg
1318
1333
|> Array.of_list
1319
1334
in
1320
1335
let live_offset = 8 * (Array.length live) in
1321
1336
(* Compute the size of stack slots for spilling all arguments of the probe. *)
1322
1337
let aux_offset = 8 (* for saving r15 *) in
1323
- let tmp_offset = 8 * (Array.length p.probe_insn.arg ) in
1324
- let loc_args, loc_offset = Proc.loc_arguments (Reg.typv p.probe_insn.arg ) in
1338
+ let tmp_offset = 8 * (Array.length h.probe_arg ) in
1339
+ let loc_args, loc_offset = Proc.loc_arguments (Reg.typv h.probe_arg ) in
1325
1340
(* Ensure the stack is aligned.
1326
1341
Assuming that the stack at the probe site is 16-byte aligned,
1327
1342
[loc_arguments] ensures that [loc_offset] is 16-byte aligned.
@@ -1345,16 +1360,16 @@ let emit_probe_handler_wrapper p =
1345
1360
I.mov r15 (reg saved_r15);
1346
1361
(* Spill all arguments of the probe. Some of these may already be on the
1347
1362
stack, in which case a temporary is used for the move. *)
1348
- let tmp = Array.mapi (make_stack_loc ~offset:loc_offset) p.probe_insn.arg in
1363
+ let tmp = Array.mapi (make_stack_loc ~offset:loc_offset) h.probe_arg in
1349
1364
Array.iteri (fun i reg -> move_allowing_stack_to_stack reg (tmp.(i)))
1350
- p.probe_insn.arg ;
1365
+ h.probe_arg ;
1351
1366
(* Load probe arguments to correct locations for the handler *)
1352
1367
Array.iteri (fun i reg -> move_allowing_stack_to_stack tmp.(i) reg) loc_args;
1353
1368
(* Reload spilled registers used as temporaries *)
1354
1369
I.mov (reg saved_r15) r15;
1355
1370
(* Emit call to handler *)
1356
- add_used_symbol handler_code_sym ;
1357
- emit_call handler_code_sym ;
1371
+ add_used_symbol h.probe_handler_code_sym ;
1372
+ emit_call h.probe_handler_code_sym ;
1358
1373
(* Record a frame description for the wrapper *)
1359
1374
let label = new_label () in
1360
1375
let live_offset =
@@ -1383,7 +1398,7 @@ let emit_probe_handler_wrapper p =
1383
1398
cfi_endproc ();
1384
1399
emit_function_type_and_size wrap_label
1385
1400
1386
- let emit_probe_notes0 () =
1401
+ let emit_probe_notes0 probes =
1387
1402
begin match system with
1388
1403
| S_gnu | S_cygwin | S_solaris | S_win32 | S_linux_elf | S_bsd_elf
1389
1404
| S_beos | S_mingw | S_win64 | S_linux | S_mingw64 | S_unknown ->
@@ -1403,18 +1418,16 @@ let emit_probe_notes0 () =
1403
1418
Printf.sprintf "%d@%s" (Reg.size_of_contents_in_bytes arg) arg_name
1404
1419
in
1405
1420
let describe_one_probe p =
1406
- let probe_name =
1407
- match p.probe_insn.desc with
1408
- | Lop (Iprobe { name; _; }) -> name
1409
- | _ -> assert false
1410
- in
1411
1421
let args =
1412
- Array.fold_right (fun arg acc -> (stap_arg arg)::acc)
1413
- p.probe_insn.arg
1414
- []
1415
- |> String.concat " "
1422
+ match p.probe_handler with
1423
+ | None -> ""
1424
+ | Some h ->
1425
+ Array.fold_right (fun arg acc -> (stap_arg arg)::acc)
1426
+ h.probe_arg
1427
+ []
1428
+ |> String.concat " "
1416
1429
in
1417
- let semaphore_label = emit_symbol (find_or_add_semaphore probe_name) in
1430
+ let semaphore_label = emit_symbol (find_or_add_semaphore p. probe_name) in
1418
1431
D.align 4;
1419
1432
let a = new_label() in
1420
1433
let b = new_label() in
@@ -1440,13 +1453,13 @@ let emit_probe_notes0 () =
1440
1453
D.qword (const 0)
1441
1454
end;
1442
1455
D.qword (ConstLabel semaphore_label);
1443
- D.bytes "ocaml.1 \000";
1444
- D.bytes (probe_name ^ "\000");
1456
+ D.bytes "ocaml.2 \000";
1457
+ D.bytes (p. probe_name ^ "\000");
1445
1458
D.bytes (args ^ "\000");
1446
1459
def_label d;
1447
1460
D.align 4;
1448
1461
in
1449
- List.iter describe_one_probe ! probes;
1462
+ List.iter describe_one_probe probes;
1450
1463
begin match system with
1451
1464
| S_gnu | S_cygwin | S_solaris | S_win32 | S_linux_elf | S_bsd_elf
1452
1465
| S_beos | S_mingw | S_win64 | S_linux | S_mingw64 | S_unknown ->
@@ -1475,10 +1488,49 @@ let emit_probe_notes0 () =
1475
1488
add_def_symbol label)
1476
1489
!probe_semaphores
1477
1490
1478
- let emit_probe_notes () =
1479
- match !probes with
1480
- | [] -> ()
1481
- | _ -> emit_probe_notes0 ()
1491
+ let emit_probe_notes probes =
1492
+ match probes, String.Map.is_empty !probe_semaphores with
1493
+ | [], true -> ()
1494
+ | _ -> emit_probe_notes0 probes
1495
+
1496
+ let emit_dummy_probe_sites () =
1497
+ let semaphores_without_probes =
1498
+ List.fold_left (fun acc probe ->
1499
+ String.Map.remove probe.probe_name acc)
1500
+ !probe_semaphores !probes in
1501
+ if (String.Map.is_empty semaphores_without_probes) then []
1502
+ else begin
1503
+ let fun_name = Compilenv.make_symbol (Some "___dummy_probes") in
1504
+
1505
+ (* start the function (as in fundecl) *)
1506
+ emit_named_text_section fun_name;
1507
+ D.align 16;
1508
+ add_def_symbol fun_name;
1509
+ D.global (emit_symbol fun_name);
1510
+ D.label (emit_symbol fun_name);
1511
+ cfi_startproc ();
1512
+
1513
+ (* emit dummy probe sites: labeled NOP only for stapsdt probes to work,
1514
+ but no calls to probe wrapper because there is no ocaml probe handler. *)
1515
+ let dummy_probes =
1516
+ String.Map.fold (fun probe_name _label acc ->
1517
+ let probe_label = new_label () in
1518
+ def_label probe_label;
1519
+ I.nop (); (* for uprobes and usdt probes as well *)
1520
+ let probe = { probe_name;
1521
+ probe_label;
1522
+ probe_handler = None;
1523
+ }
1524
+ in
1525
+ probe :: acc)
1526
+ semaphores_without_probes []
1527
+ in
1528
+ I.ret ();
1529
+ (* end the function (as in fundecl) *)
1530
+ cfi_endproc ();
1531
+ emit_function_type_and_size fun_name;
1532
+ dummy_probes
1533
+ end
1482
1534
1483
1535
let end_assembly() =
1484
1536
if !float_constants <> [] then begin
@@ -1495,6 +1547,9 @@ let end_assembly() =
1495
1547
(* Emit probe handler wrappers *)
1496
1548
List.iter emit_probe_handler_wrapper !probes;
1497
1549
1550
+ (* Emit dummy probes for semaphores without probes in this compilation unit. *)
1551
+ let dummy_probes = emit_dummy_probe_sites () in
1552
+
1498
1553
emit_named_text_section (Compilenv.make_symbol (Some "code_end"));
1499
1554
if system = S_macosx then I.nop ();
1500
1555
(* suppress "ld warning: atom sorting error" *)
@@ -1544,7 +1599,7 @@ let end_assembly() =
1544
1599
D.size frametable (ConstSub (ConstThis, ConstLabel frametable))
1545
1600
end;
1546
1601
1547
- emit_probe_notes ();
1602
+ emit_probe_notes (dummy_probes @ !probes );
1548
1603
1549
1604
if system = S_linux then
1550
1605
(* Mark stack as non-executable, PR#4564 *)
0 commit comments