aboutsummaryrefslogtreecommitdiffstats
path: root/debug/CtoDwarf.ml
blob: 4fea8f2147d8ac74574805762c6afa4b9e7b2b77 (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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
(* *********************************************************************)
(*                                                                     *)
(*              The Compcert verified compiler                         *)
(*                                                                     *)
(*          Bernhard Schommer, AbsInt Angewandte Informatik GmbH       *)
(*                                                                     *)
(*  AbsInt Angewandte Informatik GmbH. All rights reserved. This file  *)
(*  is distributed under the terms of the INRIA Non-Commercial         *)
(*  License Agreement.                                                 *)
(*                                                                     *)
(* *********************************************************************)

open C
open Cprint
open Cutil
open C2C
open DwarfTypes
open DwarfUtil
open Env

(* Functions to translate a C Ast into Dwarf 2 debugging information *)


(* Hashtable from type name to entry id *)
let type_table: (string, int) Hashtbl.t = Hashtbl.create 7

(* Hashtable for typedefname to entry id *)
let typedef_table: (string, int) Hashtbl.t = Hashtbl.create 7

(* Hashtable from composite table to entry id *)
let composite_types_table: (string, int) Hashtbl.t = Hashtbl.create 7

let get_composite_type (name: string): int =
  try 
    Hashtbl.find composite_types_table name
  with Not_found ->
    let id = next_id () in
    Hashtbl.add composite_types_table name id;
    id


let typ_to_string (ty: typ) =
  let buf = Buffer.create 7 in
  let chan = Format.formatter_of_buffer buf in
  typ chan ty;
  Format.pp_print_flush chan ();
  Buffer.contents buf

let rec mmap f env = function
  | [] -> ([],env)
  | hd :: tl ->
      let (hd',env1) = f env hd in
      let (tl', env2) = mmap f env1 tl in
      (hd' :: tl', env2)

let attr_to_dw attr_list id entries =
  List.fold_left (fun (id,entry) attr ->
    match attr with
    | AConst -> let const_tag = DW_TAG_const_type ({const_type = id;}) in
      let const_entry = new_entry const_tag in
      const_entry.id,const_entry::entry
    | AVolatile ->  let volatile_tag = DW_TAG_volatile_type ({volatile_type = id;}) in
      let volatile_entry = new_entry volatile_tag in
      volatile_entry.id,volatile_entry::entry
    | ARestrict 
    | AAlignas _
    | Attr _ -> id,entry) (id,entries) (List.rev attr_list)
let attr_to_dw_tag attr_list tag =
  let entry = new_entry tag in
  attr_to_dw attr_list entry.id [entry]


let rec type_to_dwarf (typ: typ): int * dw_entry list =
  let typ_string = typ_to_string typ in
  try
    Hashtbl.find type_table typ_string,[]
  with Not_found ->
    let id,entries = 
      match typ with
      | TVoid at -> let void = {
          base_type_byte_size = 0;
          base_type_encoding = None;
          base_type_name = "void";
        } in
        attr_to_dw_tag at (DW_TAG_base_type void)
      | TInt (k,at) ->
          let encoding =
            (match k with
            | IBool -> DW_ATE_boolean
            | IChar -> (if !Machine.config.Machine.char_signed then DW_ATE_signed_char else DW_ATE_unsigned_char) 
            | ILong | ILongLong | IShort | ISChar -> DW_ATE_signed_char
            | _ -> DW_ATE_unsigned)in
          let int = {
            base_type_byte_size = sizeof_ikind k;
            base_type_encoding = Some encoding;
            base_type_name = typ_string;} in
          attr_to_dw_tag at (DW_TAG_base_type int)
      | TFloat (k,at) ->
          let byte_size = sizeof_fkind k in
          let float = {
            base_type_byte_size = byte_size;
            base_type_encoding = Some DW_ATE_float;
            base_type_name = typ_string;
          } in
          attr_to_dw_tag at (DW_TAG_base_type float)
      | TPtr (t,at) ->
          let t,e = type_to_dwarf t in
          let pointer = {pointer_type = t;} in
          let t,e2 = attr_to_dw_tag at (DW_TAG_pointer_type pointer) in
          t,e2@e
      | TFun (rt,args,_,at) ->
          let ret,et = (match rt with
          | TVoid _ -> None,[] (* Void return *)
          | _ -> let ret,et = type_to_dwarf rt in
            Some ret,et) in
          let prototyped,children,others =
            (match args with 
            | None -> 
                let u = {
                  unspecified_parameter_file_loc = None;
                  unspecified_parameter_artificial = None;
                } in
                let u = new_entry (DW_TAG_unspecified_parameter u) in 
                false,[u],[]
            | Some [] -> true,[],[]
            | Some l ->
                let c,e = mmap (fun acc (_,t) ->
                  let t,e = type_to_dwarf t in
                  let fp =
                    {
                     formal_parameter_file_loc = None;
                     formal_parameter_artificial = None;
                     formal_parameter_location = None;
                     formal_parameter_name = None;
                     formal_parameter_segment = None;
                     formal_parameter_type = t;
                     formal_parameter_variable_parameter = None;
                   } in
                  let entry = new_entry (DW_TAG_formal_parameter fp) in
                  entry,(e@acc)) [] l in
                true,c,e) in
          let s = {
            subroutine_type = ret;
            subroutine_prototyped = prototyped;
          } in
          let s = new_entry (DW_TAG_subroutine_type s) in
          let s = add_children s children in
          attr_to_dw at s.id ((s::others)@et)
      | TStruct (i,at)
      | TUnion (i,at)
      | TEnum (i,at) ->
          let t = get_composite_type i.name in
          attr_to_dw at t []
      | TNamed (i,at) ->
          let t = Hashtbl.find typedef_table i.name in
          attr_to_dw at t []
      | TArray (child,size,at) ->
          let size_to_subrange s =
            let b = (match s with 
            | None -> None
            | Some i ->
                let i = Int64.to_int i in
                Some (BoundConst i)) in
            let s = {
              subrange_type = None;
              subrange_upper_bound = b;
            } in
            new_entry (DW_TAG_subrange_type s) in 
          let rec aux t = 
            (match t with
            | TArray (child,size,_) ->
                let sub = size_to_subrange size in
                let t,c,e = aux child in
                t,sub::c,e
            | _ -> let t,e = type_to_dwarf t in
            t,[],e) in
          let t,children,e = aux child in
          let sub = size_to_subrange size in
          let children = List.rev (sub::children) in
          let arr = {
            array_type_file_loc = None;
            array_type = t;
          } in
          let arr = new_entry (DW_TAG_array_type arr) in
          let arr = add_children arr children in
          attr_to_dw at arr.id (arr::e)          
    in
    Hashtbl.add type_table typ_string id;
    id,entries
        
let rec globdecl_to_dwarf env decl =
  match decl.gdesc with
  | Gtypedef (n,t) ->
      let i,t = type_to_dwarf t in
      Hashtbl.add typedef_table n.name i;
      let td = {
        typedef_file_loc = Some (decl.gloc);
        typedef_name = n.name;
        typedef_type = i;
      } in 
      let td = new_entry (DW_TAG_typedef td) in
      td::t     
  | Gdecl (s,n,t,_) ->
      let i,t = type_to_dwarf t in
      let at_decl = (match s with
      | Storage_extern -> true
      | _ -> false) in
      let ext = (match s with
      | Storage_static -> false
      | _ -> true) in
      let decl = {
        variable_file_loc = (Some decl.gloc);
        variable_declaration = Some at_decl;
        variable_external = Some ext;
        variable_location = None;
        variable_name = n.name;
        variable_segment = None;
        variable_type = i;
      } in
      let decl = new_entry (DW_TAG_variable decl) in
      decl::t
  | Gfundef f -> 
      let ret,e = (match f.fd_ret with
      | TVoid _ -> None,[]
      | _ -> let i,t = type_to_dwarf f.fd_ret in
        Some i,t) in
      let ext = (match f.fd_storage with
      | Storage_static -> false
      | _ -> true) in
      let fdef = {
        subprogram_file_loc = (Some decl.gloc);
        subprogram_external = Some ext;
        subprogram_frame_base = None;
        subprogram_name = f.fd_name.name;
        subprogram_prototyped = true;
        subprogram_type = ret;
      } in
      let fp,e =  mmap (fun acc (p,t) ->
        let t,e = type_to_dwarf t in
        let fp =
          {
           formal_parameter_file_loc = None;
           formal_parameter_artificial = None;
           formal_parameter_location = None;
           formal_parameter_name = (Some p.name);
           formal_parameter_segment = None;
           formal_parameter_type = t;
           formal_parameter_variable_parameter = None;
         } in
        let entry = new_entry (DW_TAG_formal_parameter fp) in
        entry,(e@acc)) e f.fd_params in
      let fdef = new_entry (DW_TAG_subprogram fdef) in
      let fdef = add_children fdef fp in
      fdef::e
  | Genumdef (n,at,e) -> 
      let bs = sizeof_ikind enum_ikind in
      let enum = {
        enumeration_file_loc = Some decl.gloc;
        enumeration_byte_size = bs;
        enumeration_declaration = Some false;
        enumeration_name = n.name;
      } in
      let id = get_composite_type n.name in
      let child = List.map (fun (i,c,_) ->
        new_entry (DW_TAG_enumerator (
                   {
                    enumerator_file_loc = None;
                    enumerator_value = Int64.to_int c;
                    enumerator_name = i.name;
                  }))) e in
      let enum = 
        {
         tag = DW_TAG_enumeration_type enum;
         children = child;
         id = id;} in
      [enum]
  | Gcompositedef (sou,n,at,m) ->
      let info = composite_info_def env sou at m in
      let dec = (match info.ci_sizeof with 
      | Some _ -> false 
      | None ->  true) in
      let tag = (match sou with
      | Struct ->
          DW_TAG_structure_type {
          structure_file_loc = Some decl.gloc;
          structure_byte_size = info.ci_sizeof;
          structure_declaration = Some dec;
          structure_name = n.name;
        }
      | Union ->
          DW_TAG_union_type {
          union_file_loc = Some decl.gloc;
          union_byte_size = info.ci_sizeof;
          union_declaration = Some dec;
          union_name = n.name;
        }) in
      let id = get_composite_type n.name in
      let children,e = 
        (match sou with
        | Struct -> 
            (* This is the same layout used in Cutil *)
            let rec pack acc bcc l m =
              match m with
              | [] -> acc,bcc,[]
              | m::ms as ml ->
                 (match m.fld_bitfield with
                 | None -> acc,bcc,ml
                 | Some n ->
                     if n = 0 then
                       acc,bcc,ms (* bit width 0 means end of pack *)
                     else if l + n > 8 * !Machine.config.Machine.sizeof_int then
                       acc,bcc,ml (* doesn't fit in current word *)
                     else
                       let t,e = type_to_dwarf m.fld_typ in
                       let um = {
                        member_file_loc = None;
                        member_byte_size = Some !Machine.config.Machine.sizeof_int;
                        member_bit_offset = Some l;
                        member_bit_size = Some n;
                        member_data_member_location = None;
                        member_declaration = None;
                        member_name = m.fld_name;
                        member_type = t;
                      } in
                       pack ((new_entry (DW_TAG_member um))::acc) (e@bcc) (l + n) ms)
            and translate acc bcc m =
              match m with
                [] -> acc,bcc
              | m::ms as ml ->
                  (match m.fld_bitfield with
                  | None -> 
                      let t,e = type_to_dwarf m.fld_typ in
                      let um = {
                        member_file_loc = None;
                        member_byte_size = None;
                        member_bit_offset = None;
                        member_bit_size = None;
                        member_data_member_location = None;
                        member_declaration = None;
                        member_name = m.fld_name;
                        member_type = t;
                      } in
                      translate ((new_entry (DW_TAG_member um))::acc) (e@bcc) ms
                  | Some _ -> let acc,bcc,rest = pack acc bcc 0 ml in 
                    translate acc bcc rest)
            in
            let children,e = translate [] []  m in
            List.rev children,e
        | Union -> mmap 
              (fun  acc f ->
                let t,e = type_to_dwarf f.fld_typ in
                let um = {
                  member_file_loc = None;
                  member_byte_size = None;
                  member_bit_offset = None;
                  member_bit_size = None;
                  member_data_member_location = None;
                  member_declaration = None;
                  member_name = f.fld_name;
                  member_type = t;
               } in
                new_entry (DW_TAG_member um),e@acc)[] m) in
      let sou = {
        tag = tag;
        children = children;
        id = id;} in
      sou::e
  | Gcompositedecl _
  | Gpragma _ -> []       

let program_to_dwarf prog name =
  Hashtbl.reset type_table;
  Hashtbl.reset composite_types_table;
  Hashtbl.reset typedef_table;
  let prog = cleanupGlobals (prog) in
  let env = translEnv Env.empty prog in
  reset_id ();
  let defs = List.concat (List.map (globdecl_to_dwarf env) prog) in
  let cp = {
    compile_unit_name = name;
  } in
  let cp = new_entry (DW_TAG_compile_unit cp) in
  add_children cp defs