Rename binary, implement query-abi, ...
* The binary is renamed from solo5-elftool to osolo5-elftool to allow for distinguishing from the binary from solo5 * query_abi is implemented and osolo5-elftool is extended with a query-abi sub command * instead of [assert false] on unknown manifest entry types or abi targets an [Error (`Msg ...)] is returned.
This commit is contained in:
parent
c1863a2f5a
commit
d3c7b0cd00
4 changed files with 124 additions and 12 deletions
2
bin/dune
2
bin/dune
|
@ -1,4 +1,4 @@
|
||||||
(executable
|
(executable
|
||||||
(public_name solo5-elftool)
|
(public_name osolo5-elftool)
|
||||||
(name main)
|
(name main)
|
||||||
(libraries solo5-elftool owee cstruct cmdliner))
|
(libraries solo5-elftool owee cstruct cmdliner))
|
||||||
|
|
20
bin/main.ml
20
bin/main.ml
|
@ -4,6 +4,11 @@ let query_manifest file =
|
||||||
|> Result.iter (fun mft ->
|
|> Result.iter (fun mft ->
|
||||||
Fmt.pr "%a\n" Solo5_elftool.pp_mft mft)
|
Fmt.pr "%a\n" Solo5_elftool.pp_mft mft)
|
||||||
|
|
||||||
|
let query_abi file =
|
||||||
|
Owee_buf.map_binary file
|
||||||
|
|> Solo5_elftool.query_abi
|
||||||
|
|> Result.iter (Fmt.pr "%a\n" Solo5_elftool.pp_abi)
|
||||||
|
|
||||||
let file =
|
let file =
|
||||||
let doc = "Solo5 executable" in
|
let doc = "Solo5 executable" in
|
||||||
Cmdliner.Arg.(required & pos 0 (some file) None &
|
Cmdliner.Arg.(required & pos 0 (some file) None &
|
||||||
|
@ -15,5 +20,18 @@ let query_manifest_cmd =
|
||||||
pure query_manifest $ file,
|
pure query_manifest $ file,
|
||||||
info ~doc "query-manifest")
|
info ~doc "query-manifest")
|
||||||
|
|
||||||
|
let query_abi_cmd =
|
||||||
|
let doc = "query solo5 abi" in
|
||||||
|
Cmdliner.Term.(
|
||||||
|
pure query_abi $ file,
|
||||||
|
info ~doc "query-abi")
|
||||||
|
|
||||||
|
let default_cmd =
|
||||||
|
Cmdliner.Term.(
|
||||||
|
ret (pure (fun man_format -> `Help (man_format, None)) $ man_format),
|
||||||
|
info "osolo5-elftool")
|
||||||
|
|
||||||
let () =
|
let () =
|
||||||
ignore (Cmdliner.Term.eval query_manifest_cmd)
|
ignore (Cmdliner.Term.eval_choice
|
||||||
|
default_cmd
|
||||||
|
[query_manifest_cmd; query_abi_cmd])
|
||||||
|
|
|
@ -12,11 +12,33 @@ type mft = {
|
||||||
entries : mft_entry list;
|
entries : mft_entry list;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mft_type_of_int : int32 -> mft_type = function
|
type abi_target =
|
||||||
| 1l -> Dev_block_basic
|
| Hvt
|
||||||
| 2l -> Dev_net_basic
|
| Spt
|
||||||
| 1073741824l -> Reserved_first
|
| Virtio
|
||||||
| _ -> assert false
|
| Muen
|
||||||
|
| Genode
|
||||||
|
| Xen
|
||||||
|
|
||||||
|
type abi = {
|
||||||
|
target : abi_target;
|
||||||
|
version : int32;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mft_type_of_int : int32 -> (mft_type, _) result = function
|
||||||
|
| 1l -> Ok Dev_block_basic
|
||||||
|
| 2l -> Ok Dev_net_basic
|
||||||
|
| 1073741824l -> Ok Reserved_first
|
||||||
|
| v -> Error (`Msg ("unknown manifest entry type: " ^ Int32.to_string v))
|
||||||
|
|
||||||
|
let abi_target_of_int : int32 -> (abi_target, _) result = function
|
||||||
|
| 1l -> Ok Hvt
|
||||||
|
| 2l -> Ok Spt
|
||||||
|
| 3l -> Ok Virtio
|
||||||
|
| 4l -> Ok Muen
|
||||||
|
| 5l -> Ok Genode
|
||||||
|
| 6l -> Ok Xen
|
||||||
|
| v -> Error (`Msg ("unknown abi target: " ^ Int32.to_string v))
|
||||||
|
|
||||||
let pp_mft_entry ppf = function
|
let pp_mft_entry ppf = function
|
||||||
| Dev_block_basic name ->
|
| Dev_block_basic name ->
|
||||||
|
@ -29,6 +51,19 @@ let pp_mft ppf { version; entries } =
|
||||||
{|{@[<1>@ "type": "solo5.manifest",@ "version": %d,@ "devices": [@[<1>@ %a@]@ ]@]@ }|}
|
{|{@[<1>@ "type": "solo5.manifest",@ "version": %d,@ "devices": [@[<1>@ %a@]@ ]@]@ }|}
|
||||||
version Fmt.(list ~sep:(append (any ",") sp) pp_mft_entry) entries
|
version Fmt.(list ~sep:(append (any ",") sp) pp_mft_entry) entries
|
||||||
|
|
||||||
|
let pp_abi_target ppf = function
|
||||||
|
| Hvt -> Format.fprintf ppf "hvt"
|
||||||
|
| Spt -> Format.fprintf ppf "spt"
|
||||||
|
| Virtio -> Format.fprintf ppf "virtio"
|
||||||
|
| Muen -> Format.fprintf ppf "muen"
|
||||||
|
| Genode -> Format.fprintf ppf "genode"
|
||||||
|
| Xen -> Format.fprintf ppf "xen"
|
||||||
|
|
||||||
|
let pp_abi ppf { version; target } =
|
||||||
|
Fmt.pf ppf
|
||||||
|
{|{@[<1>@ "type": "solo5.abi",@ "target": "%a",@ "version": %lu@ @]@ }|}
|
||||||
|
pp_abi_target target version
|
||||||
|
|
||||||
let ( let* ) = Result.bind
|
let ( let* ) = Result.bind
|
||||||
let guard m b = if not b then Error (`Msg m) else Ok ()
|
let guard m b = if not b then Error (`Msg m) else Ok ()
|
||||||
|
|
||||||
|
@ -50,7 +85,8 @@ let parse_mft_entry buf =
|
||||||
let* () = guard "non-zero mft_entry.u" (Cstruct.for_all ((=) '\000') u) in
|
let* () = guard "non-zero mft_entry.u" (Cstruct.for_all ((=) '\000') u) in
|
||||||
let* () = guard "non-zero mft_entry.b" (Cstruct.for_all ((=) '\000') b) in
|
let* () = guard "non-zero mft_entry.b" (Cstruct.for_all ((=) '\000') b) in
|
||||||
let* () = guard "non-zero mft_entry.attached" (not attached) in
|
let* () = guard "non-zero mft_entry.attached" (not attached) in
|
||||||
match mft_type_of_int typ with
|
let* typ = mft_type_of_int typ in
|
||||||
|
match typ with
|
||||||
| Reserved_first ->
|
| Reserved_first ->
|
||||||
let* () = guard "non-zero RESERVED_FIRST" (Cstruct.for_all ((=) '\000') name_raw) in
|
let* () = guard "non-zero RESERVED_FIRST" (Cstruct.for_all ((=) '\000') name_raw) in
|
||||||
Ok `Reserved_first
|
Ok `Reserved_first
|
||||||
|
@ -111,9 +147,24 @@ let parse_mft buf =
|
||||||
in
|
in
|
||||||
Ok { version = Int32.to_int version; entries }
|
Ok { version = Int32.to_int version; entries }
|
||||||
|
|
||||||
|
let parse_abi buf =
|
||||||
|
let buf = Cstruct.of_string buf in
|
||||||
|
let* () = guard "abi manifest size mismatch" (Cstruct.length buf = 4 * 4) in
|
||||||
|
let target = Cstruct.LE.get_uint32 buf 0 in
|
||||||
|
let version = Cstruct.LE.get_uint32 buf 4 in
|
||||||
|
let reserved0 = Cstruct.LE.get_uint32 buf 8 in
|
||||||
|
let reserved1 = Cstruct.LE.get_uint32 buf 12 in
|
||||||
|
let* target = abi_target_of_int target in
|
||||||
|
let* () = guard "non-zero reserved0" (reserved0 = 0l) in
|
||||||
|
let* () = guard "non-zero reserved1" (reserved1 = 0l) in
|
||||||
|
(* XXX: should we check version = 1l ? *)
|
||||||
|
Ok { target; version }
|
||||||
|
|
||||||
let ( let* ) = Result.bind
|
let ( let* ) = Result.bind
|
||||||
|
|
||||||
let mft1_note_name = "Solo5"
|
let note_name = "Solo5"
|
||||||
|
let typ_mft1 = 0x3154464d
|
||||||
|
let typ_abi1 = 0x31494241
|
||||||
|
|
||||||
let query_manifest buf =
|
let query_manifest buf =
|
||||||
let _header, sections = Owee_elf.read_elf buf in
|
let _header, sections = Owee_elf.read_elf buf in
|
||||||
|
@ -125,9 +176,26 @@ let query_manifest buf =
|
||||||
let cursor = Owee_buf.cursor body in
|
let cursor = Owee_buf.cursor body in
|
||||||
let descsz =
|
let descsz =
|
||||||
Owee_elf_notes.read_desc_size cursor
|
Owee_elf_notes.read_desc_size cursor
|
||||||
~expected_owner:mft1_note_name
|
~expected_owner:note_name
|
||||||
~expected_type:0x3154464d (* MFT1 *)
|
~expected_type:typ_mft1
|
||||||
in
|
in
|
||||||
let desc = Owee_buf.Read.fixed_string cursor descsz in
|
let desc = Owee_buf.Read.fixed_string cursor descsz in
|
||||||
let* () = guard "extra data" (Owee_buf.at_end cursor) in
|
let* () = guard "extra data" (Owee_buf.at_end cursor) in
|
||||||
parse_mft desc
|
parse_mft desc
|
||||||
|
|
||||||
|
let query_abi buf =
|
||||||
|
let _header, sections = Owee_elf.read_elf buf in
|
||||||
|
let* section =
|
||||||
|
Owee_elf.find_section sections ".note.solo5.abi"
|
||||||
|
|> Option.to_result ~none:(`Msg "section .note.solo5.abi not found")
|
||||||
|
in
|
||||||
|
let body = Owee_elf.section_body buf section in
|
||||||
|
let cursor = Owee_buf.cursor body in
|
||||||
|
let descsz =
|
||||||
|
Owee_elf_notes.read_desc_size cursor
|
||||||
|
~expected_owner:note_name
|
||||||
|
~expected_type:typ_abi1
|
||||||
|
in
|
||||||
|
let desc = Owee_buf.Read.fixed_string cursor descsz in
|
||||||
|
let* () = guard "extra data" (Owee_buf.at_end cursor) in
|
||||||
|
parse_abi desc
|
||||||
|
|
|
@ -11,11 +11,37 @@ type mft = {
|
||||||
(** [entries] in the manifest. *)
|
(** [entries] in the manifest. *)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
(** The known solo5 targets *)
|
||||||
|
type abi_target =
|
||||||
|
| Hvt
|
||||||
|
| Spt
|
||||||
|
| Virtio
|
||||||
|
| Muen
|
||||||
|
| Genode
|
||||||
|
| Xen
|
||||||
|
|
||||||
|
(** abi taget and abi version *)
|
||||||
|
type abi = {
|
||||||
|
target : abi_target; (** abi target *)
|
||||||
|
version : int32; (** abi version *)
|
||||||
|
}
|
||||||
|
|
||||||
val pp_mft_entry : Format.formatter -> mft_entry -> unit
|
val pp_mft_entry : Format.formatter -> mft_entry -> unit
|
||||||
val pp_mft : Format.formatter -> mft -> unit
|
val pp_mft : Format.formatter -> mft -> unit
|
||||||
(** Pretty-prints the manifest as JSON in a similar style as the Solo5 command
|
(** Pretty-prints the manifest as JSON in a similar style as the Solo5 command
|
||||||
* line tool {[solo5-elftool query-manifest]}. *)
|
* line tool {[solo5-elftool query-manifest]}. *)
|
||||||
|
|
||||||
|
val pp_abi_target : Format.formatter -> abi_target -> unit
|
||||||
|
val pp_abi : Format.formatter -> abi -> unit
|
||||||
|
(** Pretty-prints the manifest as JSON in a similar style as the Solo5 command
|
||||||
|
* line tool {[solo5-elftool query-abi]}. *)
|
||||||
|
|
||||||
val query_manifest : Owee_buf.t -> (mft, [> `Msg of string ]) result
|
val query_manifest : Owee_buf.t -> (mft, [> `Msg of string ]) result
|
||||||
(** [query_manifest buf] is the solo5 manifest of [buf], or an error message.
|
(** [query_manifest buf] is the solo5 manifest of [buf], or an error message.
|
||||||
* @raise Owee_buf.Invalid_format If [buf] does not contain valid ELF format *)
|
|
||||||
|
@raise Owee_buf.Invalid_format if [buf] is not valid ELF format *)
|
||||||
|
|
||||||
|
val query_abi : Owee_buf.t -> (abi, [> `Msg of string ]) result
|
||||||
|
(** [query_abi buf] is the solo5 abi of [buf], or an error message.
|
||||||
|
|
||||||
|
@raise Owee_buf.Invalid_format if [buf] is not valid ELF format *)
|
||||||
|
|
Loading…
Reference in a new issue