Skip to content

Commit

Permalink
Auto-guess the file format
Browse files Browse the repository at this point in the history
  • Loading branch information
nojb committed May 17, 2020
1 parent da3b080 commit 83ba2c4
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 102 deletions.
2 changes: 1 addition & 1 deletion tools/objinfo.ml
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ let dump_byte ic =
toc

let find_dyn_offset filename =
Bfd.find_symbol_offset ~filename (Bfd.fix_symbol_name "caml_plugin_header")
Bfd.find_symbol_offset ~filename "caml_plugin_header"

let exit_err msg = print_endline msg; exit 2
let exit_errf fmt = Printf.ksprintf exit_err fmt
Expand Down
173 changes: 73 additions & 100 deletions utils/bfd.ml
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,8 @@ end

module type S = sig
val fix_symbol_name: string -> string
val read_symbols: filename:string -> string array
val find_symbol_offset: filename:string -> string -> int64 option
val read_symbols: in_channel -> string array
val find_symbol_offset: in_channel -> string -> int64 option
end

module ELF : S = struct
Expand Down Expand Up @@ -121,18 +121,6 @@ typedef struct {
| _ -> failwith "bad data"
end

let e_shnum ehdr =
get_int16 ehdr (36 + 3 * word_size ())

let e_shentsize ehdr =
get_int16 ehdr (34 + 3 * word_size ())

let e_shoff ehdr =
get_word ehdr (24 + 2 * word_size ())

let e_shstrndx ehdr =
get_int16 ehdr (38 + 3 * word_size ())

type header =
{
e_shnum: int;
Expand All @@ -147,12 +135,12 @@ typedef struct {

let read_header ic =
seek_in ic 0;
let ehdr = really_input_bytes ic (header_size ()) in
let ehdr = really_input_bytes ic (header_size ()) in
read_magic ehdr;
let e_shnum = e_shnum ehdr in
let e_shentsize = e_shentsize ehdr in
let e_shoff = e_shoff ehdr in
let e_shstrndx = e_shstrndx ehdr in
let e_shnum = get_int16 ehdr (36 + 3 * word_size ()) in
let e_shentsize = get_int16 ehdr (34 + 3 * word_size ()) in
let e_shoff = get_word ehdr (24 + 2 * word_size ()) in
let e_shstrndx = get_int16 ehdr (38 + 3 * word_size ()) in
{e_shnum; e_shentsize; e_shoff; e_shstrndx}

(*
Expand Down Expand Up @@ -203,41 +191,32 @@ typedef struct {
Printf.fprintf oc "[%d]: %a\n" i print_section sh
) shdr

let sh_name shdr =
get_int32 shdr 0

let sh_addr shdr =
get_word shdr (8 + word_size ())
let read_section ic {sh_offset; sh_size; _} =
LargeFile.seek_in ic sh_offset;
really_input_bytes ic sh_size

let sh_offset shdr =
get_word shdr (8 + 2 * word_size ())

let sh_size shdr =
get_word shdr (8 + 3 * word_size ())

let sh_entsize shdr =
get_word shdr (16 + 5 * word_size ())

let read_section ic {sh_offset; sh_size; _} =
LargeFile.seek_in ic sh_offset;
really_input_bytes ic sh_size

let read_section_by_number ic {e_shentsize; e_shoff; _} idx =
LargeFile.seek_in ic Int64.(add e_shoff (of_int (idx * e_shentsize)));
let sh = really_input_bytes ic e_shentsize in
LargeFile.seek_in ic (sh_offset sh);
really_input_bytes ic (Int64.to_int (sh_size sh))
let shdr = really_input_bytes ic e_shentsize in
LargeFile.seek_in ic (sh_offset shdr);
really_input_bytes ic (Int64.to_int (sh_size shdr))

let read_sections ic ehdr =
let {e_shoff; e_shstrndx; e_shnum; e_shentsize} = ehdr in
let shstrtbl = read_section_by_number ic ehdr e_shstrndx in
let shstrtbl = read_section_by_number ic ehdr e_shstrndx in
LargeFile.seek_in ic e_shoff;
let mk shdr =
let sh_name = name_at shstrtbl (Int32.to_int (sh_name shdr)) in
let sh_addr = sh_addr shdr in
let sh_offset = sh_offset shdr in
let sh_size = Int64.to_int (sh_size shdr) in
let sh_entsize = Int64.to_int (sh_entsize shdr) in
let sh_name = name_at shstrtbl (Int32.to_int (get_int32 shdr 0)) in
let sh_addr = get_word shdr (8 + word_size ()) in
let sh_offset = sh_offset shdr in
let sh_size = Int64.to_int (sh_size shdr) in
let sh_entsize = Int64.to_int (get_word shdr (16 + 5 * word_size ())) in
{sh_name; sh_addr; sh_offset; sh_size; sh_entsize}
in
Array.init e_shnum (fun _ -> mk (really_input_bytes ic e_shentsize))
Expand Down Expand Up @@ -266,12 +245,6 @@ typedef struct {
} Elf64_Sym;
*)

let st_name sym =
get_int32 sym 0

let st_value sym =
get_word sym (word_size ())

let st_shndx sym =
if !is_64 then get_int16 sym 6
else get_int16 sym 14
Expand All @@ -298,8 +271,8 @@ typedef struct {
let dynstr = find_section sections ".dynstr" in
let symstrtbl = read_section ic dynstr in
let mksymbol sym =
let st_name = name_at symstrtbl (Int32.to_int (st_name sym)) in
let st_value = st_value sym in
let st_name = name_at symstrtbl (Int32.to_int (get_int32 sym 0)) in
let st_value = get_word sym (word_size ()) in
let st_shndx = st_shndx sym in
{st_name; st_value; st_shndx}
in
Expand All @@ -308,25 +281,16 @@ typedef struct {
let fix_symbol_name symname =
symname

let find_symbol_offset ~filename symname =
with_open_in filename
(fun ic ->
let ehdr = read_header ic in
let shdr = read_sections ic ehdr in
let syms = read_symbols ic shdr in
let {st_shndx; st_value; _} = find_in_array (fun {st_name; _} -> st_name = symname) syms in
Some Int64.(add shdr.(st_shndx).sh_offset (sub st_value shdr.(st_shndx).sh_addr))
)
let find_symbol_offset ic symname =
let ehdr = read_header ic in
let shdr = read_sections ic ehdr in
let syms = read_symbols ic shdr in
let {st_shndx; st_value; _} = find_in_array (fun {st_name; _} -> st_name = symname) syms in
Some Int64.(add shdr.(st_shndx).sh_offset (sub st_value shdr.(st_shndx).sh_addr))

let read_symbols ~filename =
let syms =
with_open_in filename
(fun ic ->
let ehdr = read_header ic in
read_symbols ic (read_sections ic ehdr)
)
in
Array.map (fun {st_name; _} -> st_name) syms
let read_symbols ic =
let ehdr = read_header ic in
Array.map (fun {st_name; _} -> st_name) (read_symbols ic (read_sections ic ehdr))
end

module Mach_O = struct
Expand Down Expand Up @@ -511,23 +475,20 @@ struct nlist_64 {
in
Array.init (nsyms symtab) (fun _ -> mk (really_input_bytes ic size_nlist))

let read_symbols ~filename =
with_open_in filename
(fun ic ->
let mhdr = read_header ic in
read_symbols ic (read_load_commands ic mhdr)
)
let read_symbols ic =
let mhdr = read_header ic in
read_symbols ic (read_load_commands ic mhdr)

let fix_symbol_name symname =
"_" ^ symname

let find_symbol_offset ~filename symname =
let syms = read_symbols ~filename in
let find_symbol_offset ic symname =
let syms = read_symbols ic in
let {n_value; _} = find_in_array (function {n_name; _} -> n_name = symname) syms in
Some n_value

let read_symbols ~filename =
Array.map (fun {n_name; _} -> n_name) (read_symbols ~filename)
let read_symbols ic =
Array.map (fun {n_name; _} -> n_name) (read_symbols ic)
end

module PE = struct
Expand Down Expand Up @@ -796,32 +757,44 @@ module FlexDLL = struct

let fix_symbol_name s = s

let read_symbols ~filename =
let syms =
with_open_in filename
(fun ic ->
let header, sections = PE.read ic in
read_symbols ic header sections
)
in
Array.map (fun {name; _} -> name) syms

let find_symbol_offset ~filename symname =
let offset =
with_open_in filename
(fun ic ->
let header, sections = PE.read ic in
find_symbol_offset ic header sections symname
)
in
Some offset
let read_symbols ic =
let header, sections = PE.read ic in
Array.map (fun {name; _} -> name) (read_symbols ic header sections)

let find_symbol_offset ic symname =
let header, sections = PE.read ic in
Some (find_symbol_offset ic header sections symname)
end

include (val
(match Sys.unix, Config.system with
| true, "macosx" -> (module Mach_O)
| true, _ -> (module ELF)
| false, _ -> (module FlexDLL)) : S)
let guess ic =
seek_in ic 0;
let magic = Bytes.to_string (really_input_bytes ic 4) in
match magic with
| "\x7F\x45\x4C\x46" ->
Some (module ELF : S)
| "\xFE\xED\xFA\xCE" | "\xFE\xED\xFA\xCF"
| "\xCE\xFA\xED\xFE" | "\xCF\xFA\xED\xFE" ->
Some (module Mach_O : S)
| _ when magic.[0] = 'M' && magic.[1] = 'Z' ->
Some (module FlexDLL : S)
| _ ->
None

let with_guess filename f =
with_open_in filename
(fun ic ->
match guess ic with
| Some m -> f ic m
| None -> Printf.ksprintf failwith "Cannot guess executable format of %s" filename
)

let read_symbols ~filename =
with_guess filename (fun ic (module O : S) -> O.read_symbols ic)

let find_symbol_offset ~filename symname =
with_guess filename (fun ic (module O : S) ->
O.find_symbol_offset ic (O.fix_symbol_name symname)
)

(* let () = *)
(* with_open_in Sys.argv.(1) *)
Expand Down
1 change: 0 additions & 1 deletion utils/bfd.mli
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,5 @@
(* *)
(**************************************************************************)

val fix_symbol_name: string -> string
val read_symbols: filename:string -> string array
val find_symbol_offset: filename:string -> string -> int64 option

0 comments on commit 83ba2c4

Please sign in to comment.