dwfl_report_elf.c revision d17fac7e89666b47811581b10b5ca0d253a3a82d
1/* Report a module to libdwfl based on ELF program headers. 2 Copyright (C) 2005 Red Hat, Inc. 3 4 This program is Open Source software; you can redistribute it and/or 5 modify it under the terms of the Open Software License version 1.0 as 6 published by the Open Source Initiative. 7 8 You should have received a copy of the Open Software License along 9 with this program; if not, you may obtain a copy of the Open Software 10 License version 1.0 from http://www.opensource.org/licenses/osl.php or 11 by writing the Open Source Initiative c/o Lawrence Rosen, Esq., 12 3001 King Ranch Road, Ukiah, CA 95482. */ 13 14#include "libdwflP.h" 15#include <fcntl.h> 16#include <unistd.h> 17 18 19Dwfl_Module * 20dwfl_report_elf (Dwfl *dwfl, const char *name, 21 const char *file_name, int fd, GElf_Addr base) 22{ 23 bool closefd = false; 24 25 if (fd < 0) 26 { 27 fd = open64 (file_name, O_RDONLY); 28 if (fd < 0) 29 { 30 __libdwfl_seterrno (DWFL_E_ERRNO); 31 return NULL; 32 } 33 closefd = true; 34 } 35 36 Elf *elf = elf_begin (fd, ELF_C_READ_MMAP_PRIVATE, NULL); 37 38 GElf_Ehdr ehdr_mem, *ehdr = gelf_getehdr (elf, &ehdr_mem); 39 if (ehdr == NULL) 40 { 41 elf_error: 42 __libdwfl_seterrno (DWFL_E_LIBELF); 43 if (closefd) 44 close (fd); 45 return NULL; 46 } 47 48 GElf_Addr start = 0, end = 0, bias = 0; 49 switch (ehdr->e_type) 50 { 51 case ET_REL: 52 /* For a relocatable object, we do an arbitrary section layout. 53 By updating the section header in place, we leave the layout 54 information to be found by relocation. */ 55 56 start = end = base; 57 58 Elf_Scn *scn = NULL; 59 while ((scn = elf_nextscn (elf, scn)) != NULL) 60 { 61 GElf_Shdr shdr_mem; 62 GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); 63 if (shdr == NULL) 64 goto elf_error; 65 66 if (shdr->sh_flags & SHF_ALLOC) 67 { 68 const GElf_Xword align = shdr->sh_addralign ?: 1; 69 shdr->sh_addr = (end + align - 1) & -align; 70 if (end == base) 71 /* This is the first section assigned a location. 72 Use its aligned address as the module's base. */ 73 start = shdr->sh_addr; 74 end = shdr->sh_addr + shdr->sh_size; 75 if (! gelf_update_shdr (scn, shdr)) 76 goto elf_error; 77 } 78 } 79 80 if (end == start) 81 { 82 __libdwfl_seterrno (DWFL_E_BADELF); 83 if (closefd) 84 close (fd); 85 return NULL; 86 } 87 break; 88 89 /* Everything else has to have program headers. */ 90 91 case ET_EXEC: 92 case ET_CORE: 93 /* An assigned base address is meaningless for these. */ 94 base = 0; 95 96 case ET_DYN: 97 default: 98 for (uint_fast16_t i = 0; i < ehdr->e_phnum; ++i) 99 { 100 GElf_Phdr phdr_mem, *ph = gelf_getphdr (elf, i, &phdr_mem); 101 if (ph == NULL) 102 goto elf_error; 103 if (ph->p_type == PT_LOAD) 104 { 105 if ((base & (ph->p_align - 1)) != 0) 106 base = (base + ph->p_align - 1) & -ph->p_align; 107 start = base + (ph->p_vaddr & -ph->p_align); 108 break; 109 } 110 } 111 bias = base; 112 113 for (uint_fast16_t i = ehdr->e_phnum; i-- > 0;) 114 { 115 GElf_Phdr phdr_mem, *ph = gelf_getphdr (elf, i, &phdr_mem); 116 if (ph == NULL) 117 goto elf_error; 118 if (ph->p_type == PT_LOAD) 119 { 120 end = base + (ph->p_vaddr + ph->p_memsz); 121 break; 122 } 123 } 124 125 if (end == 0) 126 { 127 __libdwfl_seterrno (DWFL_E_NO_PHDR); 128 if (closefd) 129 close (fd); 130 return NULL; 131 } 132 break; 133 } 134 135 Dwfl_Module *m = INTUSE(dwfl_report_module) (dwfl, name, start, end); 136 if (m != NULL) 137 { 138 if (m->main.name == NULL) 139 { 140 m->main.name = strdup (file_name); 141 m->main.fd = fd; 142 } 143 else if ((fd >= 0 && m->main.fd != fd) 144 || strcmp (m->main.name, file_name)) 145 { 146 elf_end (elf); 147 overlap: 148 if (closefd) 149 close (fd); 150 m->gc = true; 151 __libdwfl_seterrno (DWFL_E_OVERLAP); 152 m = NULL; 153 } 154 155 /* Preinstall the open ELF handle for the module. */ 156 if (m->main.elf == NULL) 157 { 158 m->main.elf = elf; 159 m->main.bias = bias; 160 m->e_type = ehdr->e_type; 161 } 162 else 163 { 164 elf_end (elf); 165 if (m->main.bias != base) 166 goto overlap; 167 } 168 } 169 return m; 170} 171INTDEF (dwfl_report_elf) 172