1 /* Core file handling. 2 Copyright (C) 2008-2010 Red Hat, Inc. 3 This file is part of Red Hat elfutils. 4 5 Red Hat elfutils is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by the 7 Free Software Foundation; version 2 of the License. 8 9 Red Hat elfutils is distributed in the hope that it will be useful, but 10 WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 General Public License for more details. 13 14 You should have received a copy of the GNU General Public License along 15 with Red Hat elfutils; if not, write to the Free Software Foundation, 16 Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA. 17 18 In addition, as a special exception, Red Hat, Inc. gives You the 19 additional right to link the code of Red Hat elfutils with code licensed 20 under any Open Source Initiative certified open source license 21 (http://www.opensource.org/licenses/index.php) which requires the 22 distribution of source code with any binary distribution and to 23 distribute linked combinations of the two. Non-GPL Code permitted under 24 this exception must only link to the code of Red Hat elfutils through 25 those well defined interfaces identified in the file named EXCEPTION 26 found in the source code files (the "Approved Interfaces"). The files 27 of Non-GPL Code may instantiate templates or use macros or inline 28 functions from the Approved Interfaces without causing the resulting 29 work to be covered by the GNU General Public License. Only Red Hat, 30 Inc. may make changes or additions to the list of Approved Interfaces. 31 Red Hat's grant of this exception is conditioned upon your not adding 32 any new exceptions. If you wish to add a new Approved Interface or 33 exception, please contact Red Hat. You must obey the GNU General Public 34 License in all respects for all of the Red Hat elfutils code and other 35 code used in conjunction with Red Hat elfutils except the Non-GPL Code 36 covered by this exception. If you modify this file, you may extend this 37 exception to your version of the file, but you are not obligated to do 38 so. If you do not wish to provide this exception without modification, 39 you must delete this exception statement from your version and license 40 this file solely under the GPL without exception. 41 42 Red Hat elfutils is an included package of the Open Invention Network. 43 An included package of the Open Invention Network is a package for which 44 Open Invention Network licensees cross-license their patents. No patent 45 license is granted, either expressly or impliedly, by designation as an 46 included package. Should you wish to participate in the Open Invention 47 Network licensing program, please visit www.openinventionnetwork.com 48 <http://www.openinventionnetwork.com>. */ 49 50 #include <config.h> 51 #include "../libelf/libelfP.h" /* For NOTE_ALIGN. */ 52 #undef _ 53 #include "libdwflP.h" 54 #include <gelf.h> 55 56 #include <sys/param.h> 57 #include <unistd.h> 58 #include <endian.h> 59 #include <byteswap.h> 60 #include "system.h" 61 62 63 /* This is a prototype of what a new libelf interface might be. 64 This implementation is pessimal for non-mmap cases and should 65 be replaced by more diddling inside libelf internals. */ 66 static Elf * 67 elf_begin_rand (Elf *parent, loff_t offset, loff_t size, loff_t *next) 68 { 69 if (parent == NULL) 70 return NULL; 71 72 /* On failure return, we update *NEXT to point back at OFFSET. */ 73 inline Elf *fail (int error) 74 { 75 if (next != NULL) 76 *next = offset; 77 //__libelf_seterrno (error); 78 __libdwfl_seterrno (DWFL_E (LIBELF, error)); 79 return NULL; 80 } 81 82 loff_t min = (parent->kind == ELF_K_ELF ? 83 (parent->class == ELFCLASS32 84 ? sizeof (Elf32_Ehdr) : sizeof (Elf64_Ehdr)) 85 : parent->kind == ELF_K_AR ? SARMAG 86 : 0); 87 88 if (unlikely (offset < min) 89 || unlikely (offset >= (loff_t) parent->maximum_size)) 90 return fail (ELF_E_RANGE); 91 92 /* For an archive, fetch just the size field 93 from the archive header to override SIZE. */ 94 if (parent->kind == ELF_K_AR) 95 { 96 struct ar_hdr h = { .ar_size = "" }; 97 98 if (unlikely (parent->maximum_size - offset < sizeof h)) 99 return fail (ELF_E_RANGE); 100 101 if (parent->map_address != NULL) 102 memcpy (h.ar_size, parent->map_address + parent->start_offset + offset, 103 sizeof h.ar_size); 104 else if (unlikely (pread_retry (parent->fildes, 105 h.ar_size, sizeof (h.ar_size), 106 parent->start_offset + offset 107 + offsetof (struct ar_hdr, ar_size)) 108 != sizeof (h.ar_size))) 109 return fail (ELF_E_READ_ERROR); 110 111 offset += sizeof h; 112 113 char *endp; 114 size = strtoll (h.ar_size, &endp, 10); 115 if (unlikely (endp == h.ar_size) 116 || unlikely ((loff_t) parent->maximum_size - offset < size)) 117 return fail (ELF_E_INVALID_ARCHIVE); 118 } 119 120 if (unlikely ((loff_t) parent->maximum_size - offset < size)) 121 return fail (ELF_E_RANGE); 122 123 /* Even if we fail at this point, update *NEXT to point past the file. */ 124 if (next != NULL) 125 *next = offset + size; 126 127 if (unlikely (offset == 0) 128 && unlikely (size == (loff_t) parent->maximum_size)) 129 return elf_clone (parent, parent->cmd); 130 131 /* Note the image is guaranteed live only as long as PARENT 132 lives. Using elf_memory is quite suboptimal if the whole 133 file is not mmap'd. We really should have something like 134 a generalization of the archive support. */ 135 Elf_Data *data = elf_getdata_rawchunk (parent, offset, size, ELF_T_BYTE); 136 if (data == NULL) 137 return NULL; 138 assert ((loff_t) data->d_size == size); 139 return elf_memory (data->d_buf, size); 140 } 141 142 143 int 144 dwfl_report_core_segments (Dwfl *dwfl, Elf *elf, size_t phnum, GElf_Phdr *notes) 145 { 146 if (unlikely (dwfl == NULL)) 147 return -1; 148 149 int result = 0; 150 151 if (notes != NULL) 152 notes->p_type = PT_NULL; 153 154 for (size_t ndx = 0; result >= 0 && ndx < phnum; ++ndx) 155 { 156 GElf_Phdr phdr_mem; 157 GElf_Phdr *phdr = gelf_getphdr (elf, ndx, &phdr_mem); 158 if (unlikely (phdr == NULL)) 159 { 160 __libdwfl_seterrno (DWFL_E_LIBELF); 161 return -1; 162 } 163 switch (phdr->p_type) 164 { 165 case PT_LOAD: 166 result = dwfl_report_segment (dwfl, ndx, phdr, 0, NULL); 167 break; 168 169 case PT_NOTE: 170 if (notes != NULL) 171 { 172 *notes = *phdr; 173 notes = NULL; 174 } 175 break; 176 } 177 } 178 179 return result; 180 } 181 182 /* Never read more than this much without mmap. */ 183 #define MAX_EAGER_COST 8192 184 185 static bool 186 core_file_read_eagerly (Dwfl_Module *mod, 187 void **userdata __attribute__ ((unused)), 188 const char *name __attribute__ ((unused)), 189 Dwarf_Addr start __attribute__ ((unused)), 190 void **buffer, size_t *buffer_available, 191 GElf_Off cost, GElf_Off worthwhile, 192 GElf_Off whole, 193 GElf_Off contiguous __attribute__ ((unused)), 194 void *arg, Elf **elfp) 195 { 196 Elf *core = arg; 197 198 if (whole <= *buffer_available) 199 { 200 /* All there ever was, we already have on hand. */ 201 202 if (core->map_address == NULL) 203 { 204 /* We already malloc'd the buffer. */ 205 *elfp = elf_memory (*buffer, whole); 206 if (unlikely (*elfp == NULL)) 207 return false; 208 209 (*elfp)->flags |= ELF_F_MALLOCED; 210 *buffer = NULL; 211 *buffer_available = 0; 212 return true; 213 } 214 215 /* We can use the image inside the core file directly. */ 216 *elfp = elf_begin_rand (core, *buffer - core->map_address, whole, NULL); 217 *buffer = NULL; 218 *buffer_available = 0; 219 return *elfp != NULL; 220 } 221 222 /* We don't have the whole file. 223 Figure out if this is better than nothing. */ 224 225 if (worthwhile == 0) 226 /* Caller doesn't think so. */ 227 return false; 228 229 /* 230 XXX would like to fall back to partial file via memory 231 when build id find_elf fails 232 also, link_map name may give file name from disk better than partial here 233 requires find_elf hook re-doing the magic to fall back if no file found 234 */ 235 236 if (mod->build_id_len > 0) 237 /* There is a build ID that could help us find the whole file, 238 which might be more useful than what we have. 239 We'll just rely on that. */ 240 return false; 241 242 if (core->map_address != NULL) 243 /* It's cheap to get, so get it. */ 244 return true; 245 246 /* Only use it if there isn't too much to be read. */ 247 return cost <= MAX_EAGER_COST; 248 } 249 250 bool 251 dwfl_elf_phdr_memory_callback (Dwfl *dwfl, int ndx, 252 void **buffer, size_t *buffer_available, 253 GElf_Addr vaddr, 254 size_t minread, 255 void *arg) 256 { 257 Elf *elf = arg; 258 259 if (ndx == -1) 260 { 261 /* Called for cleanup. */ 262 if (elf->map_address == NULL) 263 free (*buffer); 264 *buffer = NULL; 265 *buffer_available = 0; 266 return false; 267 } 268 269 const GElf_Off align = dwfl->segment_align ?: 1; 270 GElf_Phdr phdr; 271 272 do 273 if (unlikely (gelf_getphdr (elf, ndx++, &phdr) == NULL)) 274 return false; 275 while (phdr.p_type != PT_LOAD 276 || ((phdr.p_vaddr + phdr.p_memsz + align - 1) & -align) <= vaddr); 277 278 GElf_Off start = vaddr - phdr.p_vaddr + phdr.p_offset; 279 GElf_Off end; 280 GElf_Addr end_vaddr; 281 282 inline void update_end () 283 { 284 end = (phdr.p_offset + phdr.p_filesz + align - 1) & -align; 285 end_vaddr = (phdr.p_vaddr + phdr.p_memsz + align - 1) & -align; 286 } 287 288 update_end (); 289 290 /* Use following contiguous segments to get towards SIZE. */ 291 inline bool more (size_t size) 292 { 293 while (end <= start || end - start < size) 294 { 295 if (phdr.p_filesz < phdr.p_memsz) 296 /* This segment is truncated, so no following one helps us. */ 297 return false; 298 299 if (unlikely (gelf_getphdr (elf, ndx++, &phdr) == NULL)) 300 return false; 301 302 if (phdr.p_type == PT_LOAD) 303 { 304 if (phdr.p_offset > end 305 || phdr.p_vaddr > end_vaddr) 306 /* It's discontiguous! */ 307 return false; 308 309 update_end (); 310 } 311 } 312 return true; 313 } 314 315 /* We need at least this much. */ 316 if (! more (minread)) 317 return false; 318 319 /* See how much more we can get of what the caller wants. */ 320 (void) more (*buffer_available); 321 322 /* If it's already on hand anyway, use as much as there is. */ 323 if (elf->map_address != NULL) 324 (void) more (elf->maximum_size - start); 325 326 /* Make sure we don't look past the end of the actual file, 327 even if the headers tell us to. */ 328 if (unlikely (end > elf->maximum_size)) 329 end = elf->maximum_size; 330 331 /* If the file is too small, there is nothing at all to get. */ 332 if (unlikely (start >= end)) 333 return false; 334 335 if (elf->map_address != NULL) 336 { 337 void *contents = elf->map_address + elf->start_offset + start; 338 size_t size = end - start; 339 340 if (minread == 0) /* String mode. */ 341 { 342 const void *eos = memchr (contents, '\0', size); 343 if (unlikely (eos == NULL) || unlikely (eos == contents)) 344 return false; 345 size = eos + 1 - contents; 346 } 347 348 if (*buffer == NULL) 349 { 350 *buffer = contents; 351 *buffer_available = size; 352 } 353 else 354 { 355 *buffer_available = MIN (size, *buffer_available); 356 memcpy (*buffer, contents, *buffer_available); 357 } 358 } 359 else 360 { 361 void *into = *buffer; 362 if (*buffer == NULL) 363 { 364 *buffer_available = MIN (minread ?: 512, 365 MAX (4096, MIN (end - start, 366 *buffer_available))); 367 into = malloc (*buffer_available); 368 if (unlikely (into == NULL)) 369 { 370 __libdwfl_seterrno (DWFL_E_NOMEM); 371 return false; 372 } 373 } 374 375 ssize_t nread = pread_retry (elf->fildes, into, *buffer_available, start); 376 if (nread < (ssize_t) minread) 377 { 378 if (into != *buffer) 379 free (into); 380 if (nread < 0) 381 __libdwfl_seterrno (DWFL_E_ERRNO); 382 return false; 383 } 384 385 if (minread == 0) /* String mode. */ 386 { 387 const void *eos = memchr (into, '\0', nread); 388 if (unlikely (eos == NULL) || unlikely (eos == into)) 389 { 390 if (*buffer == NULL) 391 free (into); 392 return false; 393 } 394 nread = eos + 1 - into; 395 } 396 397 if (*buffer == NULL) 398 *buffer = into; 399 *buffer_available = nread; 400 } 401 402 return true; 403 } 404 405 int 406 dwfl_core_file_report (Dwfl *dwfl, Elf *elf) 407 { 408 size_t phnum; 409 if (unlikely (elf_getphdrnum (elf, &phnum) != 0)) 410 { 411 __libdwfl_seterrno (DWFL_E_LIBELF); 412 return -1; 413 } 414 415 /* First report each PT_LOAD segment. */ 416 GElf_Phdr notes_phdr; 417 int ndx = dwfl_report_core_segments (dwfl, elf, phnum, ¬es_phdr); 418 if (unlikely (ndx <= 0)) 419 return ndx; 420 421 /* Now sniff segment contents for modules. */ 422 int sniffed = 0; 423 ndx = 0; 424 do 425 { 426 int seg = dwfl_segment_report_module (dwfl, ndx, NULL, 427 &dwfl_elf_phdr_memory_callback, elf, 428 core_file_read_eagerly, elf); 429 if (unlikely (seg < 0)) 430 return seg; 431 if (seg > ndx) 432 { 433 ndx = seg; 434 ++sniffed; 435 } 436 else 437 ++ndx; 438 } 439 while (ndx < (int) phnum); 440 441 /* Next, we should follow the chain from DT_DEBUG. */ 442 443 const void *auxv = NULL; 444 size_t auxv_size = 0; 445 if (likely (notes_phdr.p_type == PT_NOTE)) 446 { 447 /* PT_NOTE -> NT_AUXV -> AT_PHDR -> PT_DYNAMIC -> DT_DEBUG */ 448 449 Elf_Data *notes = elf_getdata_rawchunk (elf, 450 notes_phdr.p_offset, 451 notes_phdr.p_filesz, 452 ELF_T_NHDR); 453 if (likely (notes != NULL)) 454 { 455 size_t pos = 0; 456 GElf_Nhdr nhdr; 457 size_t name_pos; 458 size_t desc_pos; 459 while ((pos = gelf_getnote (notes, pos, &nhdr, 460 &name_pos, &desc_pos)) > 0) 461 if (nhdr.n_type == NT_AUXV 462 && nhdr.n_namesz == sizeof "CORE" 463 && !memcmp (notes->d_buf + name_pos, "CORE", sizeof "CORE")) 464 { 465 auxv = notes->d_buf + desc_pos; 466 auxv_size = nhdr.n_descsz; 467 break; 468 } 469 } 470 } 471 472 /* Now we have NT_AUXV contents. From here on this processing could be 473 used for a live process with auxv read from /proc. */ 474 475 int listed = dwfl_link_map_report (dwfl, auxv, auxv_size, 476 dwfl_elf_phdr_memory_callback, elf); 477 478 /* We return the number of modules we found if we found any. 479 If we found none, we return -1 instead of 0 if there was an 480 error rather than just nothing found. If link_map handling 481 failed, we still have the sniffed modules. */ 482 return sniffed == 0 || listed > sniffed ? listed : sniffed; 483 } 484 INTDEF (dwfl_core_file_report) 485