summaryrefslogtreecommitdiff
path: root/checklink/ELF_utils.ml
blob: 4d9016005998fb46f07786884ab8a99e9e47d92b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
open ELF_types
open Library

let section_ndx_by_name_noelf (eshdra: elf32_shdr array)(name: string): int =
  match array_exists (fun eshdr -> eshdr.sh_name = name) eshdra with
  | Some sndx -> sndx
  | None      -> assert false

let section_ndx_by_name (e: elf)(name: string): int option =
  array_exists (fun eshdr -> eshdr.sh_name = name) e.e_shdra

let section_bitstring_noelf
    (bs: bitstring)(eshdra: elf32_shdr array)(sndx: int): bitstring =
  let sofs = Safe32.to_int eshdra.(sndx).sh_offset in
  let size = Safe32.to_int eshdra.(sndx).sh_size in
  Bitstring.subbitstring bs Safe.(sofs * 8) Safe.(size * 8)

let section_bitstring (e: elf): int -> bitstring =
  section_bitstring_noelf e.e_bitstring e.e_shdra

let physical_offset_of_vaddr (e: elf)(sndx: int)(vaddr: int32): int32 =
  let shdr = e.e_shdra.(sndx) in
  Int32.(add shdr.sh_offset (sub vaddr shdr.sh_addr))

let section_at_vaddr (e: elf)(vaddr: int32): int option =
  array_exists
    (fun shdr ->
      shdr.sh_addr <= vaddr && vaddr < Int32.add shdr.sh_addr shdr.sh_size
    )
    e.e_shdra

(**
   Returns the bitstring of the specified size beginning at the specified
   virtual address within the specified section.
*)
let bitstring_at_vaddr e sndx vaddr size =
  let shdr = e.e_shdra.(sndx) in
  if vaddr < shdr.sh_addr || Safe32.(shdr.sh_addr + shdr.sh_size) <= vaddr
  then None
  else
    let bs = section_bitstring e sndx in
    let bit_ofs = Safe.(8 * Safe32.(to_int (vaddr - shdr.sh_addr))) in
    Some(Bitstring.subbitstring bs bit_ofs size)

(**
   Returns the entire bitstring that begins at the specified virtual address
   within the specified section and ends at the end of the file. This is useful
   when you don't know the sections size yet.
*)
let bitstring_at_vaddr_nosize (e: elf)(sndx: int)(vaddr: int32): bitstring option =
  let shdr = e.e_shdra.(sndx) in
  if vaddr < shdr.sh_addr || Safe32.(shdr.sh_addr + shdr.sh_size) <= vaddr
  then None
  else
    let bs = section_bitstring e sndx in
    let bit_ofs = Safe.(8 * Safe32.(to_int (vaddr - shdr.sh_addr))) in
    Some(Bitstring.dropbits bit_ofs bs)

(**
   Removes symbol version for GCC's symbols.
*)
let strip_versioning (s: string): string =
  try String.sub s 0 (String.index s '@')
  with Not_found -> s

(**
   Removes CompCert's mangling of variadic functions
*)
let strip_mangling (s: string): string =
  try String.sub s 0 (String.index s '$')
  with Not_found -> s

(**
   Returns the list of all symbols matching the specified name.
*)
let ndxes_of_sym_name (e: elf) (name: string): int list =
  try StringMap.find (strip_mangling name) e.e_syms_by_name with Not_found -> []

(**
   Returns the index of the first symbol matching the specified name, if it
   exists.
*)
let ndx_of_sym_name (e: elf) (name: string): int option =
  match ndxes_of_sym_name e name with
  | [] -> None
  | h::_ -> Some(h)