1 /* Copyright (C) 2007-2010 The Android Open Source Project 2 ** 3 ** This software is licensed under the terms of the GNU General Public 4 ** License version 2, as published by the Free Software Foundation, and 5 ** may be copied, distributed, and modified under those terms. 6 ** 7 ** This program is distributed in the hope that it will be useful, 8 ** but WITHOUT ANY WARRANTY; without even the implied warranty of 9 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 ** GNU General Public License for more details. 11 */ 12 13 /* 14 * Contains declaration of a class DwarfCU, that encapsulates a compilation 15 * unit in the .debug_info section of the mapped ELF file. 16 */ 17 18 #ifndef ELFF_DWARF_CU_H_ 19 #define ELFF_DWARF_CU_H_ 20 21 #include "dwarf_defs.h" 22 #include "dwarf_die.h" 23 24 /* Address information descriptor. */ 25 typedef struct Dwarf_AddressInfo { 26 /* Routine DIE containing the address. */ 27 const DIEObject* die_obj; 28 29 /* Source file name for the address. */ 30 const char* file_name; 31 32 /* Source file directory path for the address. */ 33 const char* dir_name; 34 35 /* Source file line number for the address. */ 36 Elf_Word line_number; 37 } Dwarf_AddressInfo; 38 39 /* STMTL header cached by compilation unit. This header is contained in 40 * the .debug_line section of the ELF file. */ 41 typedef struct Dwarf_STMTL_Hdr { 42 /* The size in bytes of the line number information for this compilation 43 * unit, not including the unit_length field itself. */ 44 Elf_Xword unit_length; 45 46 /* A version number. This number is specific to the line number information 47 * and is independent of the DWARF version number. */ 48 Elf_Half version; 49 50 /* The number of bytes following the header_length field to the beginning of 51 * the first byte of the line number program itself. In the 32-bit DWARF 52 * format, this is a 4-byte unsigned length; in the 64-bit DWARF format, 53 * this field is an 8-byte unsigned length. */ 54 Elf_Xword header_length; 55 56 /* The size in bytes of the smallest target machine instruction. Line number 57 * program opcodes that alter the address register first multiply their 58 * operands by this value. */ 59 Elf_Byte min_instruction_len; 60 61 /* The initial value of the is_stmt register. */ 62 Elf_Byte default_is_stmt; 63 64 /* This parameter affects the meaning of the special opcodes. */ 65 Elf_Sbyte line_base; 66 67 /* This parameter affects the meaning of the special opcodes. */ 68 Elf_Byte line_range; 69 70 /* The number assigned to the first special opcode. */ 71 Elf_Byte opcode_base; 72 73 /* Points to standard_opcode_lengths array in the actual STMTL header in 74 * the mapped .debug_line section. */ 75 const Elf_Byte* standard_opcode_lengths; 76 77 /* Pointer to the beginning of the list of include directories in the mapped 78 * .debug_line section. */ 79 const char* include_directories; 80 81 /* Number of include directories in the list that begins with 82 * include_directories. */ 83 Elf_Word inc_dir_num; 84 85 /* Pointer to the beginning of the list of file information in the mapped 86 * .debug_line section. Each entry in this list begins with zero-terminated 87 * file name, followed by ULEB128 encoding directory index for the file, 88 * followed by ULEB128 encoding last modification time, followed by ULEB128 89 * encoding length of file in bytes. */ 90 const Dwarf_STMTL_FileDesc* file_infos; 91 92 /* Start of the "Line Number Program" in the mapped .debug_line section. */ 93 const Elf_Byte* start; 94 95 /* End of the "Line Number Program" in the mapped .debug_line section. */ 96 const Elf_Byte* end; 97 } Dwarf_STMTL_Hdr; 98 99 /* Encapsulates architecture-independent functionality of a 100 * compilation unit. 101 */ 102 class DwarfCU : public DwarfAllocBase { 103 friend class ElfFile; 104 public: 105 /* Constructs DwarfCU instance. 106 * Param: 107 * elf - Instance of ElfFile containing this compilation unit. 108 */ 109 explicit DwarfCU(ElfFile* elf); 110 111 /* Destructs DwarfCU instance. */ 112 virtual ~DwarfCU(); 113 114 /* Creates DwarfCUImpl instance, depending on DWARF format. 115 * Param: 116 * elf - Instance of ElfFile containing this compilation unit. 117 * hdr - Pointer to compilation unit header inside mapped .debug_info 118 * section of the ELF file. Actual data addressed by this pointer 119 * must be Dwarf32_CUHdr for 32 bit DWARFs, or Dwarf64_CUHdr for 120 * 64 bit DWARFs. 121 * Return: 122 * Created DwarfCUImpl instance (typecasted back to DwarfCU) on success, 123 * or NULL on failure. 124 */ 125 static DwarfCU* create_instance(ElfFile* elf, const void* hdr); 126 127 /* Process a DIE attribute. 128 * Param: 129 * attr - Attribute list inside the mapped .debug_info section of the ELF 130 * file. 131 * form - Attribute's form, definig representation of attribute value in the 132 * mapped .debug_info section of the ELF file. 133 * attr_value - Upon return contains attribute value. 134 * Return: 135 * Pointer to the next DIE attribute inside the mapped .debug_info section 136 * of the ELF file. 137 */ 138 const Elf_Byte* process_attrib(const Elf_Byte* attr, 139 Dwarf_Form form, 140 Dwarf_Value* attr_value) const; 141 142 /* Dumps this compilation unit to the stdout. */ 143 void dump() const; 144 145 /* Gets instance of ElfFile containing this compilation unit. */ elf_file()146 ElfFile* elf_file() const { 147 return elf_file_; 148 } 149 150 /* Gets DIE object for this CU. */ cu_die()151 DIEObject* cu_die() const { 152 return cu_die_; 153 } 154 155 /* Gets byte size of the pointer type for this compilation unit. */ addr_sizeof()156 Elf_Byte addr_sizeof() const { 157 return addr_sizeof_; 158 } 159 160 /* Gets full path to the compilation directory (DW_AT_comp_dir attribute). 161 * Return: 162 * Full path to the compilation directory (DW_AT_comp_dir attribute), 163 * or NULL, if that attribute was missing in CU's attribute list. 164 */ comp_dir_path()165 const char* comp_dir_path() const { 166 DIEAttrib attr; 167 return cu_die()->get_attrib(DW_AT_comp_dir, &attr) ? attr.value()->str : 168 NULL; 169 } 170 171 /* Gets relative (from the compilation directory) path to the compiled file. 172 * (DW_AT_name attribute). 173 * Return: 174 * Relative path to the compiled file (DW_AT_name attribute), or NULL, if 175 * that attribute was missing in CU's attribute list. 176 */ rel_cu_path()177 const char* rel_cu_path() const { 178 DIEAttrib attr; 179 return cu_die()->get_attrib(DW_AT_name, &attr) ? attr.value()->str : 180 NULL; 181 } 182 183 /* Gets next compilation unit in the list. NULL indicates the last CU. */ prev_cu()184 DwarfCU* prev_cu() const { 185 return prev_cu_; 186 } 187 188 /* Links this CU to the list of prevoiusly discovered CUs. */ set_prev_cu(DwarfCU * prev)189 void set_prev_cu(DwarfCU* prev) { 190 prev_cu_ = prev; 191 } 192 193 /* Checks if DWARF version for this CU is higher than 2. */ is_DWARF3_or_higher()194 bool is_DWARF3_or_higher() const { 195 return version_ >= 3; 196 } 197 198 /* Gets DIE abbreviation for given abbreviation number. 199 * See DwarfAbbrDieArray::get() */ get_die_abbr(Dwarf_AbbrNum num)200 const Dwarf_Abbr_DIE* get_die_abbr(Dwarf_AbbrNum num) const { 201 return abbrs_.get(num); 202 } 203 204 /* Gets DIE object containing given address. 205 * DIE address ranges may overlap (for instance, address range for an inlined 206 * routine will be contained within the address range of a routine where it 207 * was inlined). This method will return a DIE object that is a "leaf" in 208 * that inlining tree. I.e the returned DIE object represents the last DIE 209 * in the branch of all DIEs containing given address. 210 * Param: 211 * address - Address to get a DIE for. NOTE: for the sake of simplicity we 212 * explicitly use 64-bit type for an address. 213 * Return: 214 * Leaf DIE containing given address, or NULL if this CU doesn't contain 215 * the given address. 216 */ get_leaf_die_for_address(Elf_Xword address)217 DIEObject* get_leaf_die_for_address(Elf_Xword address) const { 218 return cu_die_->get_leaf_for_address(address); 219 } 220 221 /* Checks if this CU contains 64, or 32-bit addresses. */ is_CU_address_64()222 bool is_CU_address_64() const { 223 return addr_sizeof_ == 8; 224 } is_CU_address_32()225 bool is_CU_address_32() const { 226 return addr_sizeof_ == 4; 227 } 228 229 //============================================================================= 230 // DWARF format dependent methods 231 //============================================================================= 232 233 public: 234 /* Parses this compilation unit in .debug_info section, collecting children 235 * DIEs of this compilation unit. 236 * Param: 237 * parse_context - Parsing context that lists tags for DIEs that should be 238 * collected during parsing. NULL passed in this parameter indicates DIEs 239 * for all tags should be collected. 240 * next_cu_die - Upon successful return contains pointer to the next 241 * compilation unit descriptor inside mapped .debug_info section of 242 * the ELF file. 243 * Return: 244 * true on success, false on failure. 245 */ 246 virtual bool parse(const DwarfParseContext* parse_context, 247 const void** next_cu_die) = 0; 248 249 /* Gets a DIE object referenced by an offset from the beginning of 250 * this CU in the mapped .debug_info section. 251 */ 252 virtual DIEObject* get_referenced_die_object(Elf_Word ref) const = 0; 253 254 /* Gets a reference to a DIE object (offset of the DIE from the 255 * beginning of this CU in the mapped .debug_info section. 256 */ 257 virtual Elf_Word get_die_reference(const Dwarf_DIE* die) const = 0; 258 259 /* Gets PC address information. 260 * Param: 261 * address - PC address to get information for. 262 * info - Upon success contains information about routine that belongs to 263 * this compilation unit, containing the given address. 264 * Return: 265 * true on success, or false if this CU doesn't contain the given address. 266 */ 267 virtual bool get_pc_address_file_info(Elf_Xword address, 268 Dwarf_AddressInfo* info) = 0; 269 270 /* Gets file descriptor in the mapped .debug_line section of ELF file for a 271 * given index in the file descriptor list. 272 * Param: 273 * index - 1-based index of file descriptor in the file descriptor list. 274 * Return: 275 * File descriptor for the given index, or NULL if index was too big. 276 * NOTE: pointer returned from this method addressed mapped section of 277 * ELF file. 278 */ 279 virtual const Dwarf_STMTL_FileDesc* get_stmt_file_info(Elf_Word index) = 0; 280 281 /* Gets directory name by an index in the mapped .debug_line section of 282 * ELF file. 283 * Param: 284 * dir_index - Index of the directory in the file descriptor list. If this 285 * parameter is zero, compilation directory (DW_AT_comp_dir) for this CU 286 * will be returned. 287 * Return: 288 * Directory name for the given index, or NULL if index was too big. 289 * NOTE: pointer returned from this method addressed mapped section of 290 * ELF file. 291 */ 292 virtual const char* get_stmt_dir_name(Elf_Word dir_index) = 0; 293 294 protected: 295 /* DIE abbreviation descriptors, cached for this compilation unit. */ 296 DwarfAbbrDieArray abbrs_; 297 298 /* Instance of an ELF file that contains this compilation unit. */ 299 ElfFile* elf_file_; 300 301 /* DIE object for this CU. */ 302 DIEObject* cu_die_; 303 304 /* Next compilation unit in the list (previous in the order they've been 305 * discovered during ELF file parsing). 306 */ 307 DwarfCU* prev_cu_; 308 309 /* DWARF version for this CU. */ 310 Elf_Half version_; 311 312 /* Byte size of the pointer type for this compilation unit. */ 313 Elf_Byte addr_sizeof_; 314 }; 315 316 /* Encapsulates architecture-dependent functionality of a compilation unit. 317 * Template param: 318 * Dwarf_CUHdr - type compilation unit header in the mapped .debug_info 319 * section of ELF file. Must be: 320 * - Dwarf32_CUHdr for 32-bit DWARF, or 321 * - Dwarf64_CUHdr for 64-bit DWARF. 322 * Dwarf_Off - type for an offset field in DWARF data format. Must be: 323 * - Dwarf32_Off for 32-bit DWARF, or 324 * - Dwarf64_Off for 64-bit DWARF. 325 */ 326 template <typename Dwarf_CUHdr, typename Dwarf_Off> 327 class DwarfCUImpl : public DwarfCU { 328 public: 329 /* Constructs DwarfCU instance. 330 * Param: 331 * elf - Instance of ElfFile containing this compilation unit. 332 * hdr - Pointer to compilation unit header inside mapped .debug_info 333 * section of the ELF file. 334 */ 335 DwarfCUImpl(ElfFile* elf, const Dwarf_CUHdr* hdr); 336 337 /* Destructs DwarfCU instance. */ ~DwarfCUImpl()338 ~DwarfCUImpl() { 339 } 340 341 /* Parses this compilation unit in .debug_info section, collecting children 342 * DIEs of this compilation unit. This is an implementation of DwarfCU's 343 * abstract metod. 344 * See DwarfCU::parse(). 345 */ 346 bool parse(const DwarfParseContext* parse_context, 347 const void** next_cu_die); 348 349 /* Gets PC address information. 350 * This is an implementation of DwarfCU's abstract metod. 351 * See DwarfCU::get_pc_address_file_info(). 352 */ 353 bool get_pc_address_file_info(Elf_Xword address, Dwarf_AddressInfo* info); 354 355 /* Gets file descriptor in the mapped .debug_line section of ELF file for a 356 * given index in the file descriptor list. 357 * This is an implementation of DwarfCU's abstract metod. 358 * See DwarfCU::get_stmt_file_info(). 359 */ 360 const Dwarf_STMTL_FileDesc* get_stmt_file_info(Elf_Word index); 361 362 /* Gets directory name by an index in the mapped .debug_line section of 363 * ELF file. 364 * This is an implementation of DwarfCU's abstract metod. 365 * See DwarfCU::get_stmt_dir_name(). 366 */ 367 const char* get_stmt_dir_name(Elf_Word dir_index); 368 369 /* Gets a DIE object referenced by an offset from the beginning of 370 * this CU. This is an implementation of DwarfCU's abstract metod. 371 */ get_referenced_die_object(Elf_Word ref)372 DIEObject* get_referenced_die_object(Elf_Word ref) const { 373 const Dwarf_DIE* die = get_referenced_die(ref); 374 return cu_die_->find_die_object(die); 375 } 376 377 /* Gets a reference to a DIE object (offset of the DIE from the 378 * beginning of this CU in the mapped .debug_info section. 379 * This is an implementation of DwarfCU's abstract metod. 380 */ get_die_reference(const Dwarf_DIE * die)381 Elf_Word get_die_reference(const Dwarf_DIE* die) const { 382 return static_cast<Elf_Word>(diff_ptr(cu_header_, die)); 383 } 384 385 protected: 386 /* Process a child DIE (and all its children) in this compilation unit. 387 * Param: 388 * parse_context - See DwarfCU::parse(). 389 * die - DIE descriptor of the child to process in this method. 390 * parent_obj - Parent object of the child to process in this method. 391 * NOTE: this parameter can be NULL only for a DIE that represents this 392 * compilation unit itself. 393 * Return: 394 * Pointer to the end of child's attribute list in the mapped .debug_info 395 * section on success, or NULL on failure. Usually, pointer returned from 396 * this method is simply discarded, since parent calculates address of the 397 * next sibling's DIE based on DW_AT_sibling attribute of the DIE preceding 398 * child's DIE. 399 */ 400 const Elf_Byte* process_DIE(const DwarfParseContext* parse_context, 401 const Dwarf_DIE* die, 402 DIEObject* parent_obj); 403 404 /* Creates a DIE object for the given DIE. 405 * Param: 406 * parse_context See DwarfCU::parse(). 407 * die - DIE to create an object for. 408 * parent - Parent DIE object for the one that's being created in this 409 * method. 410 * tag - Tag of the DIE object that's being created in this method. 411 * Return: 412 * Created DIE object. This method may returns NULL in two cases: 413 * - We're not interested in this DIE (decided by looking at 'tag' 414 * parameter. In this case errno should be set to zero. 415 * - Memory allocation has failed. In this case errno should be 416 * set to ENOMEM. 417 */ 418 DIEObject* create_die_object(const DwarfParseContext* parse_context, 419 const Dwarf_DIE* die, 420 DIEObject* parent, 421 Dwarf_Tag tag); 422 423 /* Initializes (caches) STMT lines header for this CU. */ 424 bool init_stmtl(); 425 426 /* Saves current source file information, collected in the state machine by 427 * the "Line Number Program". 428 * Param: 429 * state - State machine collected "Line Number Program" results. 430 * info - Upon success contains source file information, copied over from 431 * the state machine. 432 * Return: 433 * true on success, or false on failure. 434 */ 435 bool set_source_info(const DwarfStateMachine* state, 436 Dwarf_AddressInfo* info); 437 438 /* Gets pointer to the DIE descriptor for this CU. */ get_DIE()439 const Dwarf_DIE* get_DIE() const { 440 /* CU's DIE descriptor immediately follows CU header. */ 441 return INC_CPTR_T(Dwarf_DIE, cu_header_, sizeof(Dwarf_CUHdr)); 442 } 443 444 /* Caches STMTL header from .debug_line section to stmtl_header_. 445 * Template param: 446 * Dwarf_STMTL_Hdr - Dwarf_STMTL_Hdr32, or Dwarf_STMTL_Hdr64, depending 447 * on the header type. 448 * Param: 449 * stmtl_hdr - STMTL header in the mapped .debug_line section to cache. 450 */ 451 template <typename Dwarf_STMTL_Hdr> cache_stmtl(const Dwarf_STMTL_Hdr * stmtl_hdr)452 void cache_stmtl(const Dwarf_STMTL_Hdr* stmtl_hdr) { 453 stmtl_header_.unit_length = elf_file()->pull_val(stmtl_hdr->unit_length.size); 454 stmtl_header_.version = elf_file()->pull_val(stmtl_hdr->version); 455 stmtl_header_.header_length = elf_file()->pull_val(stmtl_hdr->header_length); 456 stmtl_header_.min_instruction_len = stmtl_hdr->min_instruction_len; 457 stmtl_header_.default_is_stmt = stmtl_hdr->default_is_stmt; 458 stmtl_header_.line_base = stmtl_hdr->line_base; 459 stmtl_header_.line_range = stmtl_hdr->line_range; 460 stmtl_header_.opcode_base = stmtl_hdr->opcode_base; 461 stmtl_header_.standard_opcode_lengths = &stmtl_hdr->standard_opcode_lengths; 462 stmtl_header_.start = INC_CPTR_T(Elf_Byte, &stmtl_hdr->min_instruction_len, 463 stmtl_header_.header_length); 464 stmtl_header_.end = INC_CPTR_T(Elf_Byte, &stmtl_hdr->version, 465 stmtl_header_.unit_length); 466 stmtl_header_.include_directories = 467 INC_CPTR_T(char, stmtl_header_.standard_opcode_lengths, 468 stmtl_header_.opcode_base - 1); 469 const char* dir = stmtl_header_.include_directories; 470 while (*dir != '\0') { 471 dir += strlen(dir) + 1; 472 stmtl_header_.inc_dir_num++; 473 } 474 stmtl_header_.file_infos = INC_CPTR_T(Dwarf_STMTL_FileDesc, dir, 1); 475 } 476 477 /* Gets a DIE referenced by an offset from the beginning of this CU 478 * in the mapped .debug_info section. 479 */ get_referenced_die(Elf_Word ref)480 const Dwarf_DIE* get_referenced_die(Elf_Word ref) const { 481 return INC_CPTR_T(Dwarf_DIE, cu_header_, ref); 482 } 483 484 /* Checks if pointer to the DIE attribute is contained within the CU's area 485 * of the mapped .debug_info section. 486 * Param: 487 * ptr - Pointer to the DIE attribute to check. 488 * Return: 489 * true, if pointer to the DIE attribute is contained within the CU's area 490 * of the mapped .debug_info section, or false if attribute pointer goes 491 * beyond CU's area of the mapped .debug_info section. 492 */ is_attrib_ptr_valid(const void * ptr)493 bool is_attrib_ptr_valid(const void* ptr) const { 494 return diff_ptr(cu_header_, ptr) < cu_size_; 495 } 496 497 protected: 498 /* Pointer to this compilation unit header inside the mapped .debug_info 499 * section of the ELF file. 500 */ 501 const Dwarf_CUHdr* cu_header_; 502 503 /* Size of this compilation unit area in the mapped .debug_info section. 504 * This value has been cached off the CU header in order to avoid 505 * endianness conversions. 506 */ 507 Dwarf_Off cu_size_; 508 509 /* STMT lines header, cached off mapped .debug_line section. */ 510 Dwarf_STMTL_Hdr stmtl_header_; 511 }; 512 513 #endif // ELFF_DWARF_CU_H_ 514