| xf.li | bdd93d5 | 2023-05-12 07:10:14 -0700 | [diff] [blame] | 1 | /* Copyright (C) 1999-2016 Free Software Foundation, Inc. | 
|  | 2 | This file is part of the GNU C Library. | 
|  | 3 | Contributed by Andreas Jaeger <aj@suse.de>, 1999 and | 
|  | 4 | Jakub Jelinek <jakub@redhat.com>, 1999. | 
|  | 5 |  | 
|  | 6 | The GNU C Library is free software; you can redistribute it and/or | 
|  | 7 | modify it under the terms of the GNU Lesser General Public | 
|  | 8 | License as published by the Free Software Foundation; either | 
|  | 9 | version 2.1 of the License, or (at your option) any later version. | 
|  | 10 |  | 
|  | 11 | The GNU C Library is distributed in the hope that it will be useful, | 
|  | 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
|  | 14 | Lesser General Public License for more details. | 
|  | 15 |  | 
|  | 16 | You should have received a copy of the GNU Lesser General Public | 
|  | 17 | License along with the GNU C Library; if not, see | 
|  | 18 | <http://www.gnu.org/licenses/>.  */ | 
|  | 19 |  | 
|  | 20 | /* This code is a heavily simplified version of the readelf program | 
|  | 21 | that's part of the current binutils development version.  For architectures | 
|  | 22 | which need to handle both 32bit and 64bit ELF libraries,  this file is | 
|  | 23 | included twice for each arch size.  */ | 
|  | 24 |  | 
|  | 25 | /* check_ptr checks that a pointer is in the mmaped file and doesn't | 
|  | 26 | point outside it.  */ | 
|  | 27 | #undef check_ptr | 
|  | 28 | #define check_ptr(ptr)						\ | 
|  | 29 | do								\ | 
|  | 30 | {								\ | 
|  | 31 | if ((void *)(ptr) < file_contents				\ | 
|  | 32 | || (void *)(ptr) > (file_contents+file_length))		\ | 
|  | 33 | {								\ | 
|  | 34 | error (0, 0, _("file %s is truncated\n"), file_name);	\ | 
|  | 35 | return 1;						\ | 
|  | 36 | }								\ | 
|  | 37 | }								\ | 
|  | 38 | while (0); | 
|  | 39 |  | 
|  | 40 | /* Returns 0 if everything is ok, != 0 in case of error.  */ | 
|  | 41 | int | 
|  | 42 | process_elf_file (const char *file_name, const char *lib, int *flag, | 
|  | 43 | unsigned int *osversion, char **soname, void *file_contents, | 
|  | 44 | size_t file_length) | 
|  | 45 | { | 
|  | 46 | int i; | 
|  | 47 | unsigned int j; | 
|  | 48 | ElfW(Addr) loadaddr; | 
|  | 49 | unsigned int dynamic_addr; | 
|  | 50 | size_t dynamic_size; | 
|  | 51 | char *program_interpreter; | 
|  | 52 |  | 
|  | 53 | ElfW(Ehdr) *elf_header; | 
|  | 54 | ElfW(Phdr) *elf_pheader, *segment; | 
|  | 55 | ElfW(Dyn) *dynamic_segment, *dyn_entry; | 
|  | 56 | char *dynamic_strings; | 
|  | 57 |  | 
|  | 58 | elf_header = (ElfW(Ehdr) *) file_contents; | 
|  | 59 | *osversion = 0; | 
|  | 60 |  | 
|  | 61 | if (elf_header->e_ident [EI_CLASS] != ElfW (CLASS)) | 
|  | 62 | { | 
|  | 63 | if (opt_verbose) | 
|  | 64 | { | 
|  | 65 | if (elf_header->e_ident [EI_CLASS] == ELFCLASS32) | 
|  | 66 | error (0, 0, _("%s is a 32 bit ELF file.\n"), file_name); | 
|  | 67 | else if (elf_header->e_ident [EI_CLASS] == ELFCLASS64) | 
|  | 68 | error (0, 0, _("%s is a 64 bit ELF file.\n"), file_name); | 
|  | 69 | else | 
|  | 70 | error (0, 0, _("Unknown ELFCLASS in file %s.\n"), file_name); | 
|  | 71 | } | 
|  | 72 | return 1; | 
|  | 73 | } | 
|  | 74 |  | 
|  | 75 | if (elf_header->e_type != ET_DYN) | 
|  | 76 | { | 
|  | 77 | error (0, 0, _("%s is not a shared object file (Type: %d).\n"), file_name, | 
|  | 78 | elf_header->e_type); | 
|  | 79 | return 1; | 
|  | 80 | } | 
|  | 81 |  | 
|  | 82 | /* Get information from elf program header.  */ | 
|  | 83 | elf_pheader = (ElfW(Phdr) *) (elf_header->e_phoff + file_contents); | 
|  | 84 | check_ptr (elf_pheader); | 
|  | 85 |  | 
|  | 86 | /* The library is an elf library, now search for soname and | 
|  | 87 | libc5/libc6.  */ | 
|  | 88 | *flag = FLAG_ELF; | 
|  | 89 |  | 
|  | 90 | loadaddr = -1; | 
|  | 91 | dynamic_addr = 0; | 
|  | 92 | dynamic_size = 0; | 
|  | 93 | program_interpreter = NULL; | 
|  | 94 | for (i = 0, segment = elf_pheader; | 
|  | 95 | i < elf_header->e_phnum; i++, segment++) | 
|  | 96 | { | 
|  | 97 | check_ptr (segment); | 
|  | 98 |  | 
|  | 99 | switch (segment->p_type) | 
|  | 100 | { | 
|  | 101 | case PT_LOAD: | 
|  | 102 | if (loadaddr == (ElfW(Addr)) -1) | 
|  | 103 | loadaddr = segment->p_vaddr - segment->p_offset; | 
|  | 104 | break; | 
|  | 105 |  | 
|  | 106 | case PT_DYNAMIC: | 
|  | 107 | if (dynamic_addr) | 
|  | 108 | error (0, 0, _("more than one dynamic segment\n")); | 
|  | 109 |  | 
|  | 110 | dynamic_addr = segment->p_offset; | 
|  | 111 | dynamic_size = segment->p_filesz; | 
|  | 112 | break; | 
|  | 113 |  | 
|  | 114 | case PT_INTERP: | 
|  | 115 | program_interpreter = (char *) (file_contents + segment->p_offset); | 
|  | 116 | check_ptr (program_interpreter); | 
|  | 117 |  | 
|  | 118 | /* Check if this is enough to classify the binary.  */ | 
|  | 119 | for (j = 0; j < sizeof (interpreters) / sizeof (interpreters [0]); | 
|  | 120 | ++j) | 
|  | 121 | if (strcmp (program_interpreter, interpreters[j].soname) == 0) | 
|  | 122 | { | 
|  | 123 | *flag = interpreters[j].flag; | 
|  | 124 | break; | 
|  | 125 | } | 
|  | 126 | break; | 
|  | 127 |  | 
|  | 128 | case PT_NOTE: | 
|  | 129 | if (!*osversion && segment->p_filesz >= 32 && segment->p_align >= 4) | 
|  | 130 | { | 
|  | 131 | ElfW(Word) *abi_note = (ElfW(Word) *) (file_contents | 
|  | 132 | + segment->p_offset); | 
|  | 133 | ElfW(Addr) size = segment->p_filesz; | 
|  | 134 |  | 
|  | 135 | while (abi_note [0] != 4 || abi_note [1] != 16 | 
|  | 136 | || abi_note [2] != 1 | 
|  | 137 | || memcmp (abi_note + 3, "GNU", 4) != 0) | 
|  | 138 | { | 
|  | 139 | #define ROUND(len) (((len) + sizeof (ElfW(Word)) - 1) & -sizeof (ElfW(Word))) | 
|  | 140 | ElfW(Addr) note_size = 3 * sizeof (ElfW(Word)) | 
|  | 141 | + ROUND (abi_note[0]) | 
|  | 142 | + ROUND (abi_note[1]); | 
|  | 143 |  | 
|  | 144 | if (size - 32 < note_size || note_size == 0) | 
|  | 145 | { | 
|  | 146 | size = 0; | 
|  | 147 | break; | 
|  | 148 | } | 
|  | 149 | size -= note_size; | 
|  | 150 | abi_note = (void *) abi_note + note_size; | 
|  | 151 | } | 
|  | 152 |  | 
|  | 153 | if (size == 0) | 
|  | 154 | break; | 
|  | 155 |  | 
|  | 156 | *osversion = (abi_note [4] << 24) | | 
|  | 157 | ((abi_note [5] & 0xff) << 16) | | 
|  | 158 | ((abi_note [6] & 0xff) << 8) | | 
|  | 159 | (abi_note [7] & 0xff); | 
|  | 160 | } | 
|  | 161 | break; | 
|  | 162 |  | 
|  | 163 | default: | 
|  | 164 | break; | 
|  | 165 | } | 
|  | 166 |  | 
|  | 167 | } | 
|  | 168 | if (loadaddr == (ElfW(Addr)) -1) | 
|  | 169 | { | 
|  | 170 | /* Very strange. */ | 
|  | 171 | loadaddr = 0; | 
|  | 172 | } | 
|  | 173 |  | 
|  | 174 | /* Now we can read the dynamic sections.  */ | 
|  | 175 | if (dynamic_size == 0) | 
|  | 176 | return 1; | 
|  | 177 |  | 
|  | 178 | dynamic_segment = (ElfW(Dyn) *) (file_contents + dynamic_addr); | 
|  | 179 | check_ptr (dynamic_segment); | 
|  | 180 |  | 
|  | 181 | /* Find the string table.  */ | 
|  | 182 | dynamic_strings = NULL; | 
|  | 183 | for (dyn_entry = dynamic_segment; dyn_entry->d_tag != DT_NULL; | 
|  | 184 | ++dyn_entry) | 
|  | 185 | { | 
|  | 186 | check_ptr (dyn_entry); | 
|  | 187 | if (dyn_entry->d_tag == DT_STRTAB) | 
|  | 188 | { | 
|  | 189 | dynamic_strings = (char *) (file_contents + dyn_entry->d_un.d_val - loadaddr); | 
|  | 190 | check_ptr (dynamic_strings); | 
|  | 191 | break; | 
|  | 192 | } | 
|  | 193 | } | 
|  | 194 |  | 
|  | 195 | if (dynamic_strings == NULL) | 
|  | 196 | return 1; | 
|  | 197 |  | 
|  | 198 | /* Now read the DT_NEEDED and DT_SONAME entries.  */ | 
|  | 199 | for (dyn_entry = dynamic_segment; dyn_entry->d_tag != DT_NULL; | 
|  | 200 | ++dyn_entry) | 
|  | 201 | { | 
|  | 202 | if (dyn_entry->d_tag == DT_NEEDED || dyn_entry->d_tag == DT_SONAME) | 
|  | 203 | { | 
|  | 204 | char *name = dynamic_strings + dyn_entry->d_un.d_val; | 
|  | 205 | check_ptr (name); | 
|  | 206 |  | 
|  | 207 | if (dyn_entry->d_tag == DT_NEEDED) | 
|  | 208 | { | 
|  | 209 |  | 
|  | 210 | if (*flag == FLAG_ELF) | 
|  | 211 | { | 
|  | 212 | /* Check if this is enough to classify the binary.  */ | 
|  | 213 | for (j = 0; | 
|  | 214 | j < sizeof (known_libs) / sizeof (known_libs [0]); | 
|  | 215 | ++j) | 
|  | 216 | if (strcmp (name, known_libs [j].soname) == 0) | 
|  | 217 | { | 
|  | 218 | *flag = known_libs [j].flag; | 
|  | 219 | break; | 
|  | 220 | } | 
|  | 221 | } | 
|  | 222 | } | 
|  | 223 |  | 
|  | 224 | else if (dyn_entry->d_tag == DT_SONAME) | 
|  | 225 | *soname = xstrdup (name); | 
|  | 226 |  | 
|  | 227 | /* Do we have everything we need?  */ | 
|  | 228 | if (*soname && *flag != FLAG_ELF) | 
|  | 229 | return 0; | 
|  | 230 | } | 
|  | 231 | } | 
|  | 232 |  | 
|  | 233 | return 0; | 
|  | 234 | } |