aboutsummaryrefslogtreecommitdiffstats
path: root/elff/dwarf_cu.h
blob: a8f05783609223ebf4358075fbe02a05e0863cb1 (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
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
/* Copyright (C) 2007-2010 The Android Open Source Project
**
** This software is licensed under the terms of the GNU General Public
** License version 2, as published by the Free Software Foundation, and
** may be copied, distributed, and modified under those terms.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.
*/

/*
 * Contains declaration of a class DwarfCU, that encapsulates a compilation
 * unit in the .debug_info section of the mapped ELF file.
 */

#ifndef ELFF_DWARF_CU_H_
#define ELFF_DWARF_CU_H_

#include "dwarf_defs.h"
#include "dwarf_die.h"

/* Address information descriptor. */
typedef struct Dwarf_AddressInfo {
  /* Routine DIE containing the address. */
  const DIEObject*  die_obj;

  /* Source file name for the address. */
  const char*       file_name;

  /* Source file directory path for the address. */
  const char*       dir_name;

  /* Source file line number for the address. */
  Elf_Word          line_number;
} Dwarf_AddressInfo;

/* STMTL header cached by compilation unit. This header is contained in
 * the .debug_line section of the ELF file. */
typedef struct Dwarf_STMTL_Hdr {
  /* The size in bytes of the line number information for this compilation
   * unit, not including the unit_length field itself. */
  Elf_Xword                   unit_length;

  /* A version number. This number is specific to the line number information
   * and is independent of the DWARF version number. */
  Elf_Half                    version;

  /* The number of bytes following the header_length field to the beginning of
   * the first byte of the line number program itself. In the 32-bit DWARF
   * format, this is a 4-byte unsigned length; in the 64-bit DWARF format,
   * this field is an 8-byte unsigned length. */
  Elf_Xword                   header_length;

  /* The size in bytes of the smallest target machine instruction. Line number
   * program opcodes that alter the address register first multiply their
   * operands by this value. */
  Elf_Byte                    min_instruction_len;

  /* The initial value of the is_stmt register. */
  Elf_Byte                    default_is_stmt;

  /* This parameter affects the meaning of the special opcodes. */
  Elf_Sbyte                   line_base;

  /* This parameter affects the meaning of the special opcodes. */
  Elf_Byte                    line_range;

  /* The number assigned to the first special opcode. */
  Elf_Byte                    opcode_base;

  /* Points to standard_opcode_lengths array in the actual STMTL header in
   * the mapped .debug_line section. */
  const Elf_Byte*             standard_opcode_lengths;

  /* Pointer to the beginning of the list of include directories in the mapped
   * .debug_line section. */
  const char*                 include_directories;

  /* Number of include directories in the list that begins with
   * include_directories. */
  Elf_Word                    inc_dir_num;

  /* Pointer to the beginning of the list of file information in the mapped
   * .debug_line section. Each entry in this list begins with zero-terminated
   * file name, followed by ULEB128 encoding directory index for the file,
   * followed by ULEB128 encoding last modification time, followed by ULEB128
   * encoding length of file in bytes. */
  const Dwarf_STMTL_FileDesc* file_infos;

  /* Start of the "Line Number Program" in the mapped .debug_line section. */
  const Elf_Byte*             start;

  /* End of the "Line Number Program" in the mapped .debug_line section. */
  const Elf_Byte*             end;
} Dwarf_STMTL_Hdr;

/* Encapsulates architecture-independent functionality of a
 * compilation unit.
 */
class DwarfCU : public DwarfAllocBase {
friend class ElfFile;
 public:
  /* Constructs DwarfCU instance.
   * Param:
   *  elf - Instance of ElfFile containing this compilation unit.
   */
  explicit DwarfCU(ElfFile* elf);

  /* Destructs DwarfCU instance. */
  virtual ~DwarfCU();

  /* Creates DwarfCUImpl instance, depending on DWARF format.
   * Param:
   *  elf - Instance of ElfFile containing this compilation unit.
   *  hdr - Pointer to compilation unit header inside mapped .debug_info
   *    section of the ELF file. Actual data addressed by this pointer
   *    must be Dwarf32_CUHdr for 32 bit DWARFs, or Dwarf64_CUHdr for
   *    64 bit DWARFs.
   * Return:
   *  Created DwarfCUImpl instance (typecasted back to DwarfCU) on success,
   *  or NULL on failure.
   */
  static DwarfCU* create_instance(ElfFile* elf, const void* hdr);

  /* Process a DIE attribute.
   * Param:
   *  attr - Attribute list inside the mapped .debug_info section of the ELF
   *    file.
   *  form - Attribute's form, definig representation of attribute value in the
   *    mapped .debug_info section of the ELF file.
   *  attr_value - Upon return contains attribute value.
   * Return:
   *  Pointer to the next DIE attribute inside the mapped .debug_info section
   *  of the ELF file.
   */
  const Elf_Byte* process_attrib(const Elf_Byte* attr,
                                 Dwarf_Form form,
                                 Dwarf_Value* attr_value) const;

  /* Dumps this compilation unit to the stdout. */
  void dump() const;

  /* Gets instance of ElfFile containing this compilation unit. */
  ElfFile* elf_file() const {
    return elf_file_;
  }

  /* Gets DIE object for this CU. */
  DIEObject* cu_die() const {
    return cu_die_;
  }

  /* Gets byte size of the pointer type for this compilation unit. */
  Elf_Byte addr_sizeof() const {
    return addr_sizeof_;
  }

  /* Gets full path to the compilation directory (DW_AT_comp_dir attribute).
   * Return:
   *  Full path to the compilation directory (DW_AT_comp_dir attribute),
   *  or NULL, if that attribute was missing in CU's attribute list.
   */
  const char* comp_dir_path() const {
    DIEAttrib attr;
    return cu_die()->get_attrib(DW_AT_comp_dir, &attr) ? attr.value()->str :
                                                         NULL;
  }

  /* Gets relative (from the compilation directory) path to the compiled file.
   * (DW_AT_name attribute).
   * Return:
   *  Relative path to the compiled file (DW_AT_name attribute), or NULL, if
   *  that attribute was missing in CU's attribute list.
   */
  const char* rel_cu_path() const {
    DIEAttrib attr;
    return cu_die()->get_attrib(DW_AT_name, &attr) ? attr.value()->str :
                                                     NULL;
  }

  /* Gets next compilation unit in the list. NULL indicates the last CU. */
  DwarfCU* prev_cu() const {
    return prev_cu_;
  }

  /* Links this CU to the list of prevoiusly discovered CUs. */
  void set_prev_cu(DwarfCU* prev) {
    prev_cu_ = prev;
  }

  /* Checks if DWARF version for this CU is higher than 2. */
  bool is_DWARF3_or_higher() const {
    return version_ >= 3;
  }

  /* Gets DIE abbreviation for given abbreviation number.
   * See DwarfAbbrDieArray::get() */
  const Dwarf_Abbr_DIE* get_die_abbr(Dwarf_AbbrNum num) const {
    return abbrs_.get(num);
  }

  /* Gets DIE object containing given address.
   * DIE address ranges may overlap (for instance, address range for an inlined
   * routine will be contained within the address range of a routine where it
   * was inlined). This method will return a DIE object that is a "leaf" in
   * that inlining tree. I.e the returned DIE object represents the last DIE
   * in the branch of all DIEs containing given address.
   * Param:
   *  address - Address to get a DIE for. NOTE: for the sake of simplicity we
   *    explicitly use 64-bit type for an address.
   * Return:
   *  Leaf DIE containing given address, or NULL if this CU doesn't contain
   *  the given address.
   */
  DIEObject* get_leaf_die_for_address(Elf_Xword address) const {
    return cu_die_->get_leaf_for_address(address);
  }

  /* Checks if this CU contains 64, or 32-bit addresses. */
  bool is_CU_address_64() const {
    return addr_sizeof_ == 8;
  }
  bool is_CU_address_32() const {
    return addr_sizeof_ == 4;
  }

//=============================================================================
// DWARF format dependent methods
//=============================================================================

 public:
  /* Parses this compilation unit in .debug_info section, collecting children
   * DIEs of this compilation unit.
   * Param:
   *  parse_context - Parsing context that lists tags for DIEs that should be
   *    collected during parsing. NULL passed in this parameter indicates DIEs
   *    for all tags should be collected.
   *  next_cu_die - Upon successful return contains pointer to the next
   *    compilation unit descriptor inside mapped .debug_info section of
   *    the ELF file.
   * Return:
   *  true on success, false on failure.
   */
  virtual bool parse(const DwarfParseContext* parse_context,
                     const void** next_cu_die) = 0;

  /* Gets a DIE object referenced by an offset from the beginning of
   * this CU in the mapped .debug_info section.
   */
  virtual DIEObject* get_referenced_die_object(Elf_Word ref) const = 0;

  /* Gets a reference to a DIE object (offset of the DIE from the
   * beginning of this CU in the mapped .debug_info section.
   */
  virtual Elf_Word get_die_reference(const Dwarf_DIE* die) const = 0;

  /* Gets PC address information.
   * Param:
   *  address - PC address to get information for.
   *  info - Upon success contains information about routine that belongs to
   *    this compilation unit, containing the given address.
   * Return:
   *  true on success, or false if this CU doesn't contain the given address.
   */
  virtual bool get_pc_address_file_info(Elf_Xword address,
                                        Dwarf_AddressInfo* info) = 0;

  /* Gets file descriptor in the mapped .debug_line section of ELF file for a
   * given index in the file descriptor list.
   * Param:
   *  index - 1-based index of file descriptor in the file descriptor list.
   * Return:
   *  File descriptor for the given index, or NULL if index was too big.
   *  NOTE: pointer returned from this method addressed mapped section of
   *  ELF file.
   */
  virtual const Dwarf_STMTL_FileDesc* get_stmt_file_info(Elf_Word index) = 0;

  /* Gets directory name by an index in the mapped .debug_line section of
   * ELF file.
   * Param:
   *  dir_index - Index of the directory in the file descriptor list. If this
   *    parameter is zero, compilation directory (DW_AT_comp_dir) for this CU
   *    will be returned.
   * Return:
   *  Directory name for the given index, or NULL if index was too big.
   *  NOTE: pointer returned from this method addressed mapped section of
   *  ELF file.
   */
  virtual const char* get_stmt_dir_name(Elf_Word dir_index) = 0;

 protected:
  /* DIE abbreviation descriptors, cached for this compilation unit. */
  DwarfAbbrDieArray   abbrs_;

  /* Instance of an ELF file that contains this compilation unit. */
  ElfFile*            elf_file_;

  /* DIE object for this CU. */
  DIEObject*          cu_die_;

  /* Next compilation unit in the list (previous in the order they've been
   * discovered during ELF file parsing).
   */
  DwarfCU*            prev_cu_;

  /* DWARF version for this CU. */
  Elf_Half            version_;

  /* Byte size of the pointer type for this compilation unit. */
  Elf_Byte            addr_sizeof_;
};

/* Encapsulates architecture-dependent functionality of a compilation unit.
 * Template param:
 *  Dwarf_CUHdr - type compilation unit header in the mapped .debug_info
 *    section of ELF file. Must be:
 *    - Dwarf32_CUHdr for 32-bit DWARF, or
 *    - Dwarf64_CUHdr for 64-bit DWARF.
 *  Dwarf_Off - type for an offset field in DWARF data format. Must be:
 *    - Dwarf32_Off for 32-bit DWARF, or
 *    - Dwarf64_Off for 64-bit DWARF.
 */
template <typename Dwarf_CUHdr, typename Dwarf_Off>
class DwarfCUImpl : public DwarfCU {
 public:
  /* Constructs DwarfCU instance.
   * Param:
   *  elf - Instance of ElfFile containing this compilation unit.
   *  hdr - Pointer to compilation unit header inside mapped .debug_info
   *    section of the ELF file.
   */
  DwarfCUImpl(ElfFile* elf, const Dwarf_CUHdr* hdr);

  /* Destructs DwarfCU instance. */
  ~DwarfCUImpl() {
  }

  /* Parses this compilation unit in .debug_info section, collecting children
   * DIEs of this compilation unit. This is an implementation of DwarfCU's
   * abstract metod.
   * See DwarfCU::parse().
   */
  bool parse(const DwarfParseContext* parse_context,
             const void** next_cu_die);

  /* Gets PC address information.
   * This is an implementation of DwarfCU's abstract metod.
   * See DwarfCU::get_pc_address_file_info().
   */
  bool get_pc_address_file_info(Elf_Xword address, Dwarf_AddressInfo* info);

  /* Gets file descriptor in the mapped .debug_line section of ELF file for a
   * given index in the file descriptor list.
   * This is an implementation of DwarfCU's abstract metod.
   * See DwarfCU::get_stmt_file_info().
   */
  const Dwarf_STMTL_FileDesc* get_stmt_file_info(Elf_Word index);

  /* Gets directory name by an index in the mapped .debug_line section of
   * ELF file.
   * This is an implementation of DwarfCU's abstract metod.
   * See DwarfCU::get_stmt_dir_name().
   */
  const char* get_stmt_dir_name(Elf_Word dir_index);

  /* Gets a DIE object referenced by an offset from the beginning of
   * this CU. This is an implementation of DwarfCU's abstract metod.
   */
  DIEObject* get_referenced_die_object(Elf_Word ref) const {
    const Dwarf_DIE* die = get_referenced_die(ref);
    return cu_die_->find_die_object(die);
  }

  /* Gets a reference to a DIE object (offset of the DIE from the
   * beginning of this CU in the mapped .debug_info section.
   * This is an implementation of DwarfCU's abstract metod.
   */
  Elf_Word get_die_reference(const Dwarf_DIE* die) const {
    return static_cast<Elf_Word>(diff_ptr(cu_header_, die));
  }

 protected:
  /* Process a child DIE (and all its children) in this compilation unit.
   * Param:
   *  parse_context - See DwarfCU::parse().
   *  die - DIE descriptor of the child to process in this method.
   *  parent_obj - Parent object of the child to process in this method.
   *    NOTE: this parameter can be NULL only for a DIE that represents this
   *    compilation unit itself.
   * Return:
   *  Pointer to the end of child's attribute list in the mapped .debug_info
   *  section on success, or NULL on failure. Usually, pointer returned from
   *  this method is simply discarded, since parent calculates address of the
   *  next sibling's DIE based on DW_AT_sibling attribute of the DIE preceding
   *  child's DIE.
   */
  const Elf_Byte* process_DIE(const DwarfParseContext* parse_context,
                              const Dwarf_DIE* die,
                              DIEObject* parent_obj);

  /* Creates a DIE object for the given DIE.
   * Param:
   *  parse_context See DwarfCU::parse().
   *  die - DIE to create an object for.
   *  parent - Parent DIE object for the one that's being created in this
   *    method.
   *  tag - Tag of the DIE object that's being created in this method.
   * Return:
   *  Created DIE object. This method may returns NULL in two cases:
   *    - We're not interested in this DIE (decided by looking at 'tag'
   *      parameter. In this case errno should be set to zero.
   *    - Memory allocation has failed. In this case errno should be
   *      set to ENOMEM.
   */
  DIEObject* create_die_object(const DwarfParseContext* parse_context,
                               const Dwarf_DIE* die,
                               DIEObject* parent,
                               Dwarf_Tag tag);

  /* Initializes (caches) STMT lines header for this CU. */
  bool init_stmtl();

  /* Saves current source file information, collected in the state machine by
   * the "Line Number Program".
   * Param:
   *  state - State machine collected "Line Number Program" results.
   *  info - Upon success contains source file information, copied over from
   *    the state machine.
   * Return:
   *  true on success, or false on failure.
   */
  bool set_source_info(const DwarfStateMachine* state,
                       Dwarf_AddressInfo* info);

  /* Gets pointer to the DIE descriptor for this CU. */
  const Dwarf_DIE* get_DIE() const {
    /* CU's DIE descriptor immediately follows CU header. */
    return INC_CPTR_T(Dwarf_DIE, cu_header_, sizeof(Dwarf_CUHdr));
  }

  /* Caches STMTL header from .debug_line section to stmtl_header_.
   * Template param:
   *  Dwarf_STMTL_Hdr - Dwarf_STMTL_Hdr32, or Dwarf_STMTL_Hdr64, depending
   *    on the header type.
   * Param:
   *  stmtl_hdr - STMTL header in the mapped .debug_line section to cache.
   */
  template <typename Dwarf_STMTL_Hdr>
  void cache_stmtl(const Dwarf_STMTL_Hdr* stmtl_hdr) {
    stmtl_header_.unit_length = elf_file()->pull_val(stmtl_hdr->unit_length.size);
    stmtl_header_.version = elf_file()->pull_val(stmtl_hdr->version);
    stmtl_header_.header_length = elf_file()->pull_val(stmtl_hdr->header_length);
    stmtl_header_.min_instruction_len = stmtl_hdr->min_instruction_len;
    stmtl_header_.default_is_stmt = stmtl_hdr->default_is_stmt;
    stmtl_header_.line_base = stmtl_hdr->line_base;
    stmtl_header_.line_range = stmtl_hdr->line_range;
    stmtl_header_.opcode_base = stmtl_hdr->opcode_base;
    stmtl_header_.standard_opcode_lengths = &stmtl_hdr->standard_opcode_lengths;
    stmtl_header_.start = INC_CPTR_T(Elf_Byte, &stmtl_hdr->min_instruction_len,
                                     stmtl_header_.header_length);
    stmtl_header_.end = INC_CPTR_T(Elf_Byte, &stmtl_hdr->version,
                                   stmtl_header_.unit_length);
    stmtl_header_.include_directories =
        INC_CPTR_T(char, stmtl_header_.standard_opcode_lengths,
                   stmtl_header_.opcode_base - 1);
    const char* dir = stmtl_header_.include_directories;
    while (*dir != '\0') {
      dir += strlen(dir) + 1;
      stmtl_header_.inc_dir_num++;
    }
    stmtl_header_.file_infos = INC_CPTR_T(Dwarf_STMTL_FileDesc, dir, 1);
  }

  /* Gets a DIE referenced by an offset from the beginning of this CU
   * in the mapped .debug_info section.
   */
  const Dwarf_DIE* get_referenced_die(Elf_Word ref) const {
    return INC_CPTR_T(Dwarf_DIE, cu_header_, ref);
  }

  /* Checks if pointer to the DIE attribute is contained within the CU's area
   * of the mapped .debug_info section.
   * Param:
   *  ptr - Pointer to the DIE attribute to check.
   * Return:
   *  true, if pointer to the DIE attribute is contained within the CU's area
   *  of the mapped .debug_info section, or false if attribute pointer goes
   *  beyond CU's area of the mapped .debug_info section.
   */
  bool is_attrib_ptr_valid(const void* ptr) const {
    return diff_ptr(cu_header_, ptr) < cu_size_;
  }

 protected:
  /* Pointer to this compilation unit header inside the mapped .debug_info
   * section of the ELF file.
   */
  const Dwarf_CUHdr*          cu_header_;

  /* Size of this compilation unit area in the mapped .debug_info section.
   * This value has been cached off the CU header in order to avoid
   * endianness conversions.
   */
  Dwarf_Off                   cu_size_;

  /* STMT lines header, cached off mapped .debug_line section. */
  Dwarf_STMTL_Hdr             stmtl_header_;
};

#endif  // ELFF_DWARF_CU_H_