da1edf3d创建于 2023年10月27日历史提交
open! Core
open! Import

module Generated_interop = struct
  [@@@disable_unused_warnings]

  (*$
    open Magic_trace_lib_cinaps_helpers.Trace_decoding_interop;;

    gen_ocaml_record recording_config;;
    gen_ocaml_record trace_meta;;
    gen_ocaml_record mmap;;
    gen_ocaml_record setup_info
  *)
  module Recording_config = struct
    type t =
      { mutable pid : int
      ; mutable data_size : int
      ; mutable aux_size : int
      ; mutable filter : string option
      ; mutable pt_fd : int
      ; mutable sb_fd : int
      }
    [@@deriving sexp]
  end

  module Trace_meta = struct
    type t =
      { mutable time_shift : int
      ; mutable time_mult : int
      ; mutable time_zero : int
      ; mutable max_nonturbo_ratio : int
      }
    [@@deriving sexp]
  end

  module Mmap = struct
    type t =
      { mutable vaddr : int
      ; mutable length : int
      ; mutable offset : int
      ; mutable filename : string
      }
    [@@deriving sexp]
  end

  module Setup_info = struct
    type t =
      { mutable initial_maps : Mmap.t list
      ; mutable trace_meta : Trace_meta.t
      ; mutable pid : int
      }
    [@@deriving sexp]
  end
  (*$*)
end

module Stub = struct
  include Generated_interop

  type c_tracing_state

  external create_empty_state
    :  unit
    -> c_tracing_state
    = "magic_recording_create_state_stub"

  external take_snapshot : c_tracing_state -> int = "magic_recording_take_snapshot_stub"

  external destroy_tracing_state
    :  c_tracing_state
    -> unit
    = "magic_recording_destroy_stub"

  external attach
    :  c_tracing_state
    -> Recording_config.t
    -> Trace_meta.t
    -> int
    = "magic_recording_attach_stub"
end

module Mmap = Stub.Mmap
module Trace_meta = Stub.Trace_meta
module Setup_info = Stub.Setup_info

let read_current_maps pid =
  Owee_linux_maps.scan_pid (Pid.to_int pid)
  |> List.filter_map
       ~f:(fun { address_start; address_end; pathname; offset; perm_execute; _ } ->
         match perm_execute with
         | false -> None
         | true ->
           let open Int64 in
           Some
             { Mmap.vaddr = to_int_exn address_start
             ; length = address_end - address_start |> to_int_exn
             ; offset = to_int_exn offset
             ; filename = pathname
             })
;;

module Tracing_state = struct
  type t = Stub.c_tracing_state

  let attach
    ?(data_size = 0x400000)
    ?(aux_size = 0x400000)
    ?filter
    ~pt_file
    ~sideband_file
    ~setup_file
    pid
    =
    let state = Stub.create_empty_state () in
    let trace_meta : Stub.Trace_meta.t =
      { time_shift = 0; time_mult = 0; time_zero = 0; max_nonturbo_ratio = 0 }
    in
    let open_fd name =
      Core_unix.openfile ~mode:[ O_RDWR; O_CREAT; O_TRUNC ] name
      |> Core_unix.File_descr.to_int
    in
    let pt_fd = open_fd pt_file in
    let sb_fd = open_fd sideband_file in
    let config : Stub.Recording_config.t =
      { pid = Pid.to_int pid; data_size; aux_size; filter; pt_fd; sb_fd }
    in
    let%map.Result () = Stub.attach state config trace_meta |> Errno.to_result in
    Out_channel.write_all
      setup_file
      ~data:
        ([%sexp
           ({ initial_maps = read_current_maps pid; trace_meta; pid = Pid.to_int pid }
            : Setup_info.t)]
         |> Sexp.to_string);
    state
  ;;

  let destroy t = Stub.destroy_tracing_state t
  let take_snapshot t = Stub.take_snapshot t |> Errno.to_result
end