• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 implementation of ElfFile classes that encapsulate an ELF file.
15  */
16 
17 #include "string.h"
18 #include "elf_file.h"
19 #include "elf_alloc.h"
20 #include "dwarf_cu.h"
21 #include "dwarf_utils.h"
22 
23 /* Tags to parse when collecting info about routines. */
24 static const Dwarf_Tag parse_rt_tags[] = {
25   DW_TAG_compile_unit,
26   DW_TAG_partial_unit,
27   DW_TAG_inlined_subroutine,
28   DW_TAG_subprogram,
29   0
30 };
31 static const DwarfParseContext parse_rt_context = { parse_rt_tags };
32 
33 //=============================================================================
34 // Base ElfFile implementation
35 //=============================================================================
36 
ElfFile()37 ElfFile::ElfFile()
38     : sec_table_(NULL),
39       elf_file_path_(NULL),
40       sec_count_(0),
41       cu_count_(0),
42       last_cu_(NULL),
43       allocator_(NULL),
44       fixed_base_address_(0),
45       is_exec_(0),
46       elf_handle_((MapFile*)-1),
47       sec_entry_size_(0) {
48 }
49 
~ElfFile()50 ElfFile::~ElfFile() {
51   DwarfCU* cu_to_del = last_cu_;
52   while (cu_to_del != NULL) {
53     DwarfCU* next_cu_to_del = cu_to_del->prev_cu_;
54     delete cu_to_del;
55     cu_to_del = next_cu_to_del;
56   }
57 
58   if (mapfile_is_valid(elf_handle_)) {
59     mapfile_close(elf_handle_);
60   }
61 
62   if (elf_file_path_ != NULL) {
63     delete[] elf_file_path_;
64   }
65 
66   if (sec_table_ != NULL) {
67     delete[] reinterpret_cast<Elf_Byte*>(sec_table_);
68   }
69 
70   /* Must be deleted last! */
71   if (allocator_ != NULL) {
72     delete allocator_;
73   }
74 }
75 
Create(const char * path)76 ElfFile* ElfFile::Create(const char* path) {
77   ElfFile* ret = NULL;
78   /* Allocate enough space on the stack to fit the largest ELF file header. */
79   Elf64_FHdr header;
80   const Elf_CommonHdr* elf_hdr = &header.common;
81 
82   assert(path != NULL && *path != '\0');
83   if (path == NULL || *path == '\0') {
84     _set_errno(EINVAL);
85     return NULL;
86   }
87 
88   /*
89    * Open ELF file, and read its header (the largest one possible).
90    */
91   MapFile* file_handle = mapfile_open(path, O_RDONLY | O_BINARY, 0);
92   if (!mapfile_is_valid(file_handle)) {
93     return NULL;
94   }
95   const ssize_t read_bytes = mapfile_read(file_handle, &header, sizeof(header));
96   mapfile_close(file_handle);
97   assert(read_bytes != -1 && read_bytes == sizeof(header));
98   if (read_bytes == -1 || read_bytes != sizeof(header)) {
99     if (read_bytes != -1) {
100       _set_errno(EINVAL);
101     }
102     return NULL;
103   }
104 
105   /* Lets see if this is an ELF file at all. */
106   if (memcmp(elf_hdr->e_ident, ELFMAG, SELFMAG) != 0) {
107     /* File is not an ELF file. */
108     _set_errno(ENOEXEC);
109     return NULL;
110   }
111 
112   /* Lets check ELF's "bitness". */
113   assert(elf_hdr->ei_info.ei_class == ELFCLASS32 ||
114          elf_hdr->ei_info.ei_class == ELFCLASS64);
115   if (elf_hdr->ei_info.ei_class != ELFCLASS32 &&
116       elf_hdr->ei_info.ei_class != ELFCLASS64) {
117     /* Neither 32, or 64-bit ELF file. Something wrong here. */
118     _set_errno(EBADF);
119     return NULL;
120   }
121 
122   /* Lets instantiate appropriate ElfFileImpl object for this ELF. */
123   if (elf_hdr->ei_info.ei_class == ELFCLASS32) {
124     ret = new ElfFileImpl<Elf32_Addr, Elf32_Off>;
125   } else {
126     ret = new ElfFileImpl<Elf64_Addr, Elf64_Off>;
127   }
128   assert(ret != NULL);
129   if (ret != NULL) {
130     if (!ret->initialize(elf_hdr, path)) {
131       delete ret;
132       ret = NULL;
133     }
134   } else {
135     _set_errno(ENOMEM);
136   }
137 
138   return ret;
139 }
140 
initialize(const Elf_CommonHdr * elf_hdr,const char * path)141 bool ElfFile::initialize(const Elf_CommonHdr* elf_hdr, const char* path) {
142   /* Must be created first! */
143   allocator_ = new ElfAllocator();
144   assert(allocator_ != NULL);
145   if (allocator_ == NULL) {
146     _set_errno(ENOMEM);
147     return false;
148   }
149 
150   /* Copy file path. */
151   size_t path_len = strlen(path) + 1;
152   elf_file_path_ = new char[path_len];
153   assert(elf_file_path_ != NULL);
154   if (elf_file_path_ == NULL) {
155     _set_errno(ENOMEM);
156     return false;
157   }
158   memcpy(elf_file_path_, path, path_len);
159 
160   /* Cache some basic ELF properties. */
161   is_ELF_64_ = elf_hdr->ei_info.ei_class == ELFCLASS64;
162   is_elf_big_endian_ = elf_hdr->ei_info.ei_data == ELFDATA2MSB;
163   same_endianness_ = is_elf_little_endian() == is_little_endian_cpu();
164   is_exec_ = elf_hdr->e_type == 2;
165 
166   /* Reopen file for further reads and mappings. */
167   elf_handle_ = mapfile_open(elf_file_path_, O_RDONLY | O_BINARY, 0);
168   return mapfile_is_valid(elf_handle_);
169 }
170 
get_pc_address_info(Elf_Xword address,Elf_AddressInfo * address_info)171 bool ElfFile::get_pc_address_info(Elf_Xword address,
172                                   Elf_AddressInfo* address_info) {
173   assert(address_info != NULL);
174   if (address_info == NULL) {
175     _set_errno(EINVAL);
176     return false;
177   }
178 
179   /* Collect routine information for all CUs in this file. */
180   if (parse_compilation_units(&parse_rt_context) == -1) {
181     return false;
182   }
183 
184   /* Iterate through the collected CUs looking for the one that
185    * contains the given address. */
186   address_info->inline_stack = NULL;
187   DwarfCU* cu = last_cu();
188   while (cu != NULL) {
189     /* Find a leaf DIE object in the current CU that contains the address. */
190     Dwarf_AddressInfo info;
191     info.die_obj = cu->get_leaf_die_for_address(address);
192     if (info.die_obj != NULL) {
193       /* Convert the address to a location inside source file. */
194       if (cu->get_pc_address_file_info(address, &info)) {
195           /* Copy location information to the returning structure. */
196           address_info->file_name = info.file_name;
197           address_info->dir_name = info.dir_name;
198           address_info->line_number = info.line_number;
199       } else {
200           address_info->file_name = NULL;
201           address_info->dir_name = NULL;
202           address_info->line_number = 0;
203       }
204 
205       /* Lets see if the DIE represents a routine (rather than
206        * a lexical block, for instance). */
207       Dwarf_Tag tag = info.die_obj->get_tag();
208       while (!dwarf_tag_is_routine(tag)) {
209         /* This is not a routine DIE. Lets loop trhough the parents of that
210          * DIE looking for the first routine DIE. */
211         info.die_obj = info.die_obj->parent_die();
212         if (info.die_obj == NULL) {
213           /* Reached compilation unit DIE. Can't go any further. */
214           address_info->routine_name = "<unknown>";
215           return true;
216         }
217         tag = info.die_obj->get_tag();
218       }
219 
220       /* Save name of the routine that contains the address. */
221       address_info->routine_name = info.die_obj->get_name();
222       if (address_info->routine_name == NULL) {
223         /* In some cases (minimum debugging info in the file) routine
224          * name may be not avaible. We, however, are obliged by API
225          * considerations to return something in this field. */
226           address_info->routine_name = "<unknown>";
227       }
228 
229       /* Lets see if address belongs to an inlined routine. */
230       if (tag != DW_TAG_inlined_subroutine) {
231         address_info->inline_stack = NULL;
232         return true;
233       }
234 
235       /*
236        * Address belongs to an inlined routine. Create inline stack.
237        */
238 
239       /* Allocate inline stack array big enough to fit all parent entries. */
240       address_info->inline_stack =
241         new Elf_InlineInfo[info.die_obj->get_level() + 1];
242       assert(address_info->inline_stack != NULL);
243       if (address_info->inline_stack == NULL) {
244         _set_errno(ENOMEM);
245         return false;
246       }
247       memset(address_info->inline_stack, 0,
248              sizeof(Elf_InlineInfo) * (info.die_obj->get_level() + 1));
249 
250       /* Reverse DIEs filling in inline stack entries for inline
251        * routine tags. */
252       int inl_index = 0;
253       do {
254         /* Save source file information. */
255         DIEAttrib file_desc;
256         if (info.die_obj->get_attrib(DW_AT_call_file, &file_desc)) {
257           const Dwarf_STMTL_FileDesc* desc =
258               cu->get_stmt_file_info(file_desc.value()->u32);
259           if (desc != NULL) {
260             address_info->inline_stack[inl_index].inlined_in_file =
261                 desc->file_name;
262             address_info->inline_stack[inl_index].inlined_in_file_dir =
263                 cu->get_stmt_dir_name(desc->get_dir_index());
264           }
265         }
266         if (address_info->inline_stack[inl_index].inlined_in_file == NULL) {
267           address_info->inline_stack[inl_index].inlined_in_file = "<unknown>";
268           address_info->inline_stack[inl_index].inlined_in_file_dir = NULL;
269         }
270 
271         /* Save source line information. */
272         if (info.die_obj->get_attrib(DW_AT_call_line, &file_desc)) {
273           address_info->inline_stack[inl_index].inlined_at_line = file_desc.value()->u32;
274         }
275 
276         /* Advance DIE to the parent routine, and save its name. */
277         info.die_obj = info.die_obj->parent_die();
278         assert(info.die_obj != NULL);
279         if (info.die_obj != NULL) {
280           tag = info.die_obj->get_tag();
281           while (!dwarf_tag_is_routine(tag)) {
282             info.die_obj = info.die_obj->parent_die();
283             if (info.die_obj == NULL) {
284               break;
285             }
286             tag = info.die_obj->get_tag();
287           }
288           if (info.die_obj != NULL) {
289             address_info->inline_stack[inl_index].routine_name =
290                 info.die_obj->get_name();
291           }
292         }
293         if (address_info->inline_stack[inl_index].routine_name == NULL) {
294           address_info->inline_stack[inl_index].routine_name = "<unknown>";
295         }
296 
297         /* Continue with the parent DIE. */
298         inl_index++;
299       } while (info.die_obj != NULL && tag == DW_TAG_inlined_subroutine);
300 
301       return true;
302     }
303     cu = cu->prev_cu();
304   }
305 
306   return false;
307 }
308 
free_pc_address_info(Elf_AddressInfo * address_info) const309 void ElfFile::free_pc_address_info(Elf_AddressInfo* address_info) const {
310   assert(address_info != NULL);
311   if (address_info != NULL && address_info->inline_stack != NULL) {
312     delete address_info->inline_stack;
313     address_info->inline_stack = NULL;
314   }
315 }
316 
317 //=============================================================================
318 // ElfFileImpl
319 //=============================================================================
320 
321 template <typename Elf_Addr, typename Elf_Off>
initialize(const Elf_CommonHdr * elf_hdr,const char * path)322 bool ElfFileImpl<Elf_Addr, Elf_Off>::initialize(const Elf_CommonHdr* elf_hdr,
323                                                 const char* path) {
324   /* Must be called first! */
325   if (!ElfFile::initialize(elf_hdr, path)) {
326     return false;
327   }
328 
329   /* Cache some header data, so later we can discard the header. */
330   const Elf_FHdr<Elf_Addr, Elf_Off>* header =
331       reinterpret_cast<const Elf_FHdr<Elf_Addr, Elf_Off>*>(elf_hdr);
332   sec_count_ = pull_val(header->e_shnum);
333   sec_entry_size_ = pull_val(header->e_shentsize);
334   fixed_base_address_ = pull_val(header->e_entry) & ~0xFFF;
335 
336   /* Cache section table (must have one!) */
337   const Elf_Off sec_table_off = pull_val(header->e_shoff);
338   assert(sec_table_off != 0 && sec_count_ != 0);
339   if (sec_table_off == 0 || sec_count_ == 0) {
340     _set_errno(EBADF);
341     return false;
342   }
343   const size_t sec_table_size = sec_count_ * sec_entry_size_;
344   sec_table_ = new Elf_Byte[sec_table_size];
345   assert(sec_table_ != NULL);
346   if (sec_table_ == NULL) {
347     _set_errno(ENOMEM);
348     return false;
349   }
350   if (mapfile_read_at(elf_handle_, sec_table_off, sec_table_,
351                       sec_table_size) < 0) {
352       return false;
353   }
354 
355   /* Map ELF's string section (must have one!). */
356   const Elf_Half str_sec_index = pull_val(header->e_shstrndx);
357   assert(str_sec_index != SHN_UNDEF);
358   if (str_sec_index == SHN_UNDEF) {
359     _set_errno(EBADF);
360     return false;
361   }
362   const Elf_SHdr<Elf_Addr, Elf_Off>* str_sec =
363       reinterpret_cast<const Elf_SHdr<Elf_Addr, Elf_Off>*>
364           (get_section_by_index(str_sec_index));
365   assert(str_sec != NULL);
366   if (str_sec == NULL) {
367     _set_errno(EBADF);
368     return false;
369   }
370   if (!string_section_.map(elf_handle_, pull_val(str_sec->sh_offset),
371                            pull_val(str_sec->sh_size))) {
372     return false;
373   }
374 
375   /* Lets determine DWARF format. According to the docs, DWARF is 64 bit, if
376    * first 4 bytes in the compilation unit header are set to 0xFFFFFFFF.
377    * .debug_info section of the ELF file begins with the first CU header. */
378   if (!map_section_by_name(".debug_info", &debug_info_)) {
379     _set_errno(EBADF);
380     return false;
381   }
382 
383   /* Note that we don't care about endianness here, since 0xFFFFFFFF is an
384    * endianness-independent value, so we don't have to pull_val here. */
385   is_DWARF_64_ =
386     *reinterpret_cast<const Elf_Word*>(debug_info_.data()) == 0xFFFFFFFF;
387 
388   return true;
389 }
390 
391 template <typename Elf_Addr, typename Elf_Off>
parse_compilation_units(const DwarfParseContext * parse_context)392 int ElfFileImpl<Elf_Addr, Elf_Off>::parse_compilation_units(
393     const DwarfParseContext* parse_context) {
394   /* Lets see if we already parsed the file. */
395   if (last_cu() != NULL) {
396     return cu_count_;
397   }
398 
399   /* Cache sections required for this parsing. */
400   if (!map_section_by_name(".debug_abbrev", &debug_abbrev_) ||
401       !map_section_by_name(".debug_ranges", &debug_ranges_) ||
402       !map_section_by_name(".debug_line", &debug_line_) ||
403       !map_section_by_name(".debug_str", &debug_str_)) {
404     _set_errno(EBADF);
405     return false;
406   }
407 
408   /* .debug_info section opens with the first CU header. */
409   const void* next_cu = debug_info_.data();
410 
411   /* Iterate through CUs until we reached the end of .debug_info section, or
412    * advanced to a CU with zero size, indicating the end of CU list for this
413    * file. */
414   while (is_valid_cu(next_cu)) {
415     /* Instatiate CU, depending on DWARF "bitness". */
416     DwarfCU* cu = DwarfCU::create_instance(this, next_cu);
417     if (cu == NULL) {
418       _set_errno(ENOMEM);
419       return -1;
420     }
421 
422     if (cu->parse(parse_context, &next_cu)) {
423       cu->set_prev_cu(last_cu_);
424       last_cu_ = cu;
425       cu_count_++;
426     } else {
427       delete cu;
428       return -1;
429     }
430   };
431 
432   return cu_count_;
433 }
434 
435 template <typename Elf_Addr, typename Elf_Off>
get_section_info_by_name(const char * name,Elf_Off * offset,Elf_Word * size)436 bool ElfFileImpl<Elf_Addr, Elf_Off>::get_section_info_by_name(const char* name,
437                                                               Elf_Off* offset,
438                                                               Elf_Word* size) {
439   const Elf_SHdr<Elf_Addr, Elf_Off>* cur_section =
440       reinterpret_cast<const Elf_SHdr<Elf_Addr, Elf_Off>*>(sec_table_);
441 
442   for (Elf_Half sec = 0; sec < sec_count_; sec++) {
443     const char* sec_name = get_str_sec_str(pull_val(cur_section->sh_name));
444     if (sec_name != NULL && strcmp(name, sec_name) == 0) {
445       *offset = pull_val(cur_section->sh_offset);
446       *size = pull_val(cur_section->sh_size);
447       return true;
448     }
449     cur_section = reinterpret_cast<const Elf_SHdr<Elf_Addr, Elf_Off>*>
450                                   (INC_CPTR(cur_section, sec_entry_size_));
451   }
452   _set_errno(EINVAL);
453   return false;
454 }
455 
456 template <typename Elf_Addr, typename Elf_Off>
map_section_by_name(const char * name,ElfMappedSection * section)457 bool ElfFileImpl<Elf_Addr, Elf_Off>::map_section_by_name(
458     const char* name,
459     ElfMappedSection* section) {
460   if (section->is_mapped()) {
461     return true;
462   }
463 
464   Elf_Off offset;
465   Elf_Word size;
466   if (!get_section_info_by_name(name, &offset, &size)) {
467     return false;
468   }
469 
470   return section->map(elf_handle_, offset, size);
471 }
472