1 /* libunwind - a platform-independent unwind library 2 3 This file is part of libunwind. 4 5 Permission is hereby granted, free of charge, to any person obtaining 6 a copy of this software and associated documentation files (the 7 "Software"), to deal in the Software without restriction, including 8 without limitation the rights to use, copy, modify, merge, publish, 9 distribute, sublicense, and/or sell copies of the Software, and to 10 permit persons to whom the Software is furnished to do so, subject to 11 the following conditions: 12 13 The above copyright notice and this permission notice shall be 14 included in all copies or substantial portions of the Software. 15 16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ 23 24 #ifdef HAVE_CONFIG_H 25 # include "config.h" 26 #endif 27 28 /* Endian detection */ 29 #include <limits.h> 30 #if defined(HAVE_BYTESWAP_H) 31 #include <byteswap.h> 32 #endif 33 #if defined(HAVE_ENDIAN_H) 34 # include <endian.h> 35 #elif defined(HAVE_SYS_ENDIAN_H) 36 # include <sys/endian.h> 37 #endif 38 #if defined(__BYTE_ORDER) && __BYTE_ORDER == __BIG_ENDIAN 39 # define WE_ARE_BIG_ENDIAN 1 40 # define WE_ARE_LITTLE_ENDIAN 0 41 #elif defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN 42 # define WE_ARE_BIG_ENDIAN 0 43 # define WE_ARE_LITTLE_ENDIAN 1 44 #elif defined(_BYTE_ORDER) && _BYTE_ORDER == _BIG_ENDIAN 45 # define WE_ARE_BIG_ENDIAN 1 46 # define WE_ARE_LITTLE_ENDIAN 0 47 #elif defined(_BYTE_ORDER) && _BYTE_ORDER == _LITTLE_ENDIAN 48 # define WE_ARE_BIG_ENDIAN 0 49 # define WE_ARE_LITTLE_ENDIAN 1 50 #elif defined(BYTE_ORDER) && BYTE_ORDER == BIG_ENDIAN 51 # define WE_ARE_BIG_ENDIAN 1 52 # define WE_ARE_LITTLE_ENDIAN 0 53 #elif defined(BYTE_ORDER) && BYTE_ORDER == LITTLE_ENDIAN 54 # define WE_ARE_BIG_ENDIAN 0 55 # define WE_ARE_LITTLE_ENDIAN 1 56 #elif defined(__386__) 57 # define WE_ARE_BIG_ENDIAN 0 58 # define WE_ARE_LITTLE_ENDIAN 1 59 #else 60 # error "Can't determine endianness" 61 #endif 62 63 #include <elf.h> 64 #include <sys/procfs.h> /* struct elf_prstatus */ 65 66 #include "_UCD_lib.h" 67 #include "_UCD_internal.h" 68 69 #define NOTE_DATA(_hdr) STRUCT_MEMBER_P((_hdr), sizeof (Elf32_Nhdr) + UNW_ALIGN((_hdr)->n_namesz, 4)) 70 #define NOTE_SIZE(_hdr) (sizeof (Elf32_Nhdr) + UNW_ALIGN((_hdr)->n_namesz, 4) + (_hdr)->n_descsz) 71 #define NOTE_NEXT(_hdr) STRUCT_MEMBER_P((_hdr), NOTE_SIZE(_hdr)) 72 #define NOTE_FITS_IN(_hdr, _size) ((_size) >= sizeof (Elf32_Nhdr) && (_size) >= NOTE_SIZE (_hdr)) 73 #define NOTE_FITS(_hdr, _end) NOTE_FITS_IN((_hdr), (unsigned long)((char *)(_end) - (char *)(_hdr))) 74 75 struct UCD_info * 76 _UCD_create(const char *filename) 77 { 78 union 79 { 80 Elf32_Ehdr h32; 81 Elf64_Ehdr h64; 82 } elf_header; 83 #define elf_header32 elf_header.h32 84 #define elf_header64 elf_header.h64 85 bool _64bits; 86 87 struct UCD_info *ui = memset(malloc(sizeof(*ui)), 0, sizeof(*ui)); 88 ui->edi.di_cache.format = -1; 89 ui->edi.di_debug.format = -1; 90 #if UNW_TARGET_IA64 91 ui->edi.ktab.format = -1; 92 #endif 93 94 int fd = ui->coredump_fd = open(filename, O_RDONLY); 95 if (fd < 0) 96 goto err; 97 ui->coredump_filename = strdup(filename); 98 99 /* No sane ELF32 file is going to be smaller then ELF64 _header_, 100 * so let's just read 64-bit sized one. 101 */ 102 if (read(fd, &elf_header64, sizeof(elf_header64)) != sizeof(elf_header64)) 103 { 104 Debug(0, "'%s' is not an ELF file\n", filename); 105 goto err; 106 } 107 108 if (memcmp(&elf_header32, ELFMAG, SELFMAG) != 0) 109 { 110 Debug(0, "'%s' is not an ELF file\n", filename); 111 goto err; 112 } 113 114 if (elf_header32.e_ident[EI_CLASS] != ELFCLASS32 115 && elf_header32.e_ident[EI_CLASS] != ELFCLASS64) 116 { 117 Debug(0, "'%s' is not a 32/64 bit ELF file\n", filename); 118 goto err; 119 } 120 121 if (WE_ARE_LITTLE_ENDIAN != (elf_header32.e_ident[EI_DATA] == ELFDATA2LSB)) 122 { 123 Debug(0, "'%s' is endian-incompatible\n", filename); 124 goto err; 125 } 126 127 _64bits = (elf_header32.e_ident[EI_CLASS] == ELFCLASS64); 128 if (_64bits && sizeof(elf_header64.e_entry) > sizeof(off_t)) 129 { 130 Debug(0, "Can't process '%s': 64-bit file " 131 "while only %ld bits are supported", 132 filename, 8L * sizeof(off_t)); 133 goto err; 134 } 135 136 /* paranoia check */ 137 if (_64bits 138 ? 0 /* todo: (elf_header64.e_ehsize != NN || elf_header64.e_phentsize != NN) */ 139 : (elf_header32.e_ehsize != 52 || elf_header32.e_phentsize != 32) 140 ) 141 { 142 Debug(0, "'%s' has wrong e_ehsize or e_phentsize\n", filename); 143 goto err; 144 } 145 146 off_t ofs = (_64bits ? elf_header64.e_phoff : elf_header32.e_phoff); 147 if (lseek(fd, ofs, SEEK_SET) != ofs) 148 { 149 Debug(0, "Can't read phdrs from '%s'\n", filename); 150 goto err; 151 } 152 unsigned size = ui->phdrs_count = (_64bits ? elf_header64.e_phnum : elf_header32.e_phnum); 153 coredump_phdr_t *phdrs = ui->phdrs = memset(malloc(size * sizeof(phdrs[0])), 0, size * sizeof(phdrs[0])); 154 if (_64bits) 155 { 156 coredump_phdr_t *cur = phdrs; 157 unsigned i = 0; 158 while (i < size) 159 { 160 Elf64_Phdr hdr64; 161 if (read(fd, &hdr64, sizeof(hdr64)) != sizeof(hdr64)) 162 { 163 Debug(0, "Can't read phdrs from '%s'\n", filename); 164 goto err; 165 } 166 cur->p_type = hdr64.p_type ; 167 cur->p_flags = hdr64.p_flags ; 168 cur->p_offset = hdr64.p_offset; 169 cur->p_vaddr = hdr64.p_vaddr ; 170 /*cur->p_paddr = hdr32.p_paddr ; always 0 */ 171 //TODO: check that and abort if it isn't? 172 cur->p_filesz = hdr64.p_filesz; 173 cur->p_memsz = hdr64.p_memsz ; 174 cur->p_align = hdr64.p_align ; 175 /* cur->backing_filename = NULL; - done by memset */ 176 cur->backing_fd = -1; 177 cur->backing_filesize = hdr64.p_filesz; 178 i++; 179 cur++; 180 } 181 } else { 182 coredump_phdr_t *cur = phdrs; 183 unsigned i = 0; 184 while (i < size) 185 { 186 Elf32_Phdr hdr32; 187 if (read(fd, &hdr32, sizeof(hdr32)) != sizeof(hdr32)) 188 { 189 Debug(0, "Can't read phdrs from '%s'\n", filename); 190 goto err; 191 } 192 cur->p_type = hdr32.p_type ; 193 cur->p_flags = hdr32.p_flags ; 194 cur->p_offset = hdr32.p_offset; 195 cur->p_vaddr = hdr32.p_vaddr ; 196 /*cur->p_paddr = hdr32.p_paddr ; always 0 */ 197 cur->p_filesz = hdr32.p_filesz; 198 cur->p_memsz = hdr32.p_memsz ; 199 cur->p_align = hdr32.p_align ; 200 /* cur->backing_filename = NULL; - done by memset */ 201 cur->backing_fd = -1; 202 cur->backing_filesize = hdr32.p_memsz; 203 i++; 204 cur++; 205 } 206 } 207 208 unsigned i = 0; 209 coredump_phdr_t *cur = phdrs; 210 while (i < size) 211 { 212 Debug(2, "phdr[%03d]: type:%d", i, cur->p_type); 213 if (cur->p_type == PT_NOTE) 214 { 215 Elf32_Nhdr *note_hdr, *note_end; 216 unsigned n_threads; 217 218 ui->note_phdr = malloc(cur->p_filesz); 219 if (lseek(fd, cur->p_offset, SEEK_SET) != (off_t)cur->p_offset 220 || (uoff_t)read(fd, ui->note_phdr, cur->p_filesz) != cur->p_filesz) 221 { 222 Debug(0, "Can't read PT_NOTE from '%s'\n", filename); 223 goto err; 224 } 225 226 note_end = STRUCT_MEMBER_P (ui->note_phdr, cur->p_filesz); 227 228 /* Count number of threads */ 229 n_threads = 0; 230 note_hdr = (Elf32_Nhdr *)ui->note_phdr; 231 while (NOTE_FITS (note_hdr, note_end)) 232 { 233 if (note_hdr->n_type == NT_PRSTATUS) 234 n_threads++; 235 236 note_hdr = NOTE_NEXT (note_hdr); 237 } 238 239 ui->n_threads = n_threads; 240 ui->threads = malloc(sizeof (void *) * n_threads); 241 242 n_threads = 0; 243 note_hdr = (Elf32_Nhdr *)ui->note_phdr; 244 while (NOTE_FITS (note_hdr, note_end)) 245 { 246 if (note_hdr->n_type == NT_PRSTATUS) 247 ui->threads[n_threads++] = NOTE_DATA (note_hdr); 248 249 note_hdr = NOTE_NEXT (note_hdr); 250 } 251 } 252 if (cur->p_type == PT_LOAD) 253 { 254 Debug(2, " ofs:%08llx va:%08llx filesize:%08llx memsize:%08llx flg:%x", 255 (unsigned long long) cur->p_offset, 256 (unsigned long long) cur->p_vaddr, 257 (unsigned long long) cur->p_filesz, 258 (unsigned long long) cur->p_memsz, 259 cur->p_flags 260 ); 261 if (cur->p_filesz < cur->p_memsz) 262 Debug(2, " partial"); 263 if (cur->p_flags & PF_X) 264 Debug(2, " executable"); 265 } 266 Debug(2, "\n"); 267 i++; 268 cur++; 269 } 270 271 if (ui->n_threads == 0) 272 { 273 Debug(0, "No NT_PRSTATUS note found in '%s'\n", filename); 274 goto err; 275 } 276 277 ui->prstatus = ui->threads[0]; 278 279 return ui; 280 281 err: 282 _UCD_destroy(ui); 283 return NULL; 284 } 285 286 int _UCD_get_num_threads(struct UCD_info *ui) 287 { 288 return ui->n_threads; 289 } 290 291 void _UCD_select_thread(struct UCD_info *ui, int n) 292 { 293 if (n >= 0 && n < ui->n_threads) 294 ui->prstatus = ui->threads[n]; 295 } 296 297 pid_t _UCD_get_pid(struct UCD_info *ui) 298 { 299 return ui->prstatus->pr_pid; 300 } 301 302 int _UCD_get_cursig(struct UCD_info *ui) 303 { 304 return ui->prstatus->pr_cursig; 305 } 306 307 int _UCD_add_backing_file_at_segment(struct UCD_info *ui, int phdr_no, const char *filename) 308 { 309 if ((unsigned)phdr_no >= ui->phdrs_count) 310 { 311 Debug(0, "There is no segment %d in this coredump\n", phdr_no); 312 return -1; 313 } 314 315 struct coredump_phdr *phdr = &ui->phdrs[phdr_no]; 316 if (phdr->backing_filename) 317 { 318 Debug(0, "Backing file already added to segment %d\n", phdr_no); 319 return -1; 320 } 321 322 int fd = open(filename, O_RDONLY); 323 if (fd < 0) 324 { 325 Debug(0, "Can't open '%s'\n", filename); 326 return -1; 327 } 328 329 phdr->backing_fd = fd; 330 phdr->backing_filename = strdup(filename); 331 332 struct stat statbuf; 333 if (fstat(fd, &statbuf) != 0) 334 { 335 Debug(0, "Can't stat '%s'\n", filename); 336 goto err; 337 } 338 phdr->backing_filesize = (uoff_t)statbuf.st_size; 339 340 if (phdr->p_flags != (PF_X | PF_R)) 341 Debug(1, "Note: phdr[%u] is not r-x: flags are 0x%x\n", phdr_no, phdr->p_flags); 342 343 if (phdr->backing_filesize > phdr->p_memsz) 344 { 345 /* This is expected */ 346 Debug(2, "Note: phdr[%u] is %lld bytes, file is larger: %lld bytes\n", 347 phdr_no, 348 (unsigned long long)phdr->p_memsz, 349 (unsigned long long)phdr->backing_filesize 350 ); 351 } 352 //TODO: else loudly complain? Maybe even fail? 353 354 if (phdr->p_filesz != 0) 355 { 356 //TODO: loop and compare in smaller blocks 357 char *core_buf = malloc(phdr->p_filesz); 358 char *file_buf = malloc(phdr->p_filesz); 359 if (lseek(ui->coredump_fd, phdr->p_offset, SEEK_SET) != (off_t)phdr->p_offset 360 || (uoff_t)read(ui->coredump_fd, core_buf, phdr->p_filesz) != phdr->p_filesz 361 ) 362 { 363 Debug(0, "Error reading from coredump file\n"); 364 err_read: 365 free(core_buf); 366 free(file_buf); 367 goto err; 368 } 369 if ((uoff_t)read(fd, file_buf, phdr->p_filesz) != phdr->p_filesz) 370 { 371 Debug(0, "Error reading from '%s'\n", filename); 372 goto err_read; 373 } 374 int r = memcmp(core_buf, file_buf, phdr->p_filesz); 375 free(core_buf); 376 free(file_buf); 377 if (r != 0) 378 { 379 Debug(1, "Note: phdr[%u] first %lld bytes in core dump and in file do not match\n", 380 phdr_no, (unsigned long long)phdr->p_filesz 381 ); 382 } else { 383 Debug(1, "Note: phdr[%u] first %lld bytes in core dump and in file match\n", 384 phdr_no, (unsigned long long)phdr->p_filesz 385 ); 386 } 387 } 388 389 /* Success */ 390 return 0; 391 392 err: 393 if (phdr->backing_fd >= 0) 394 { 395 close(phdr->backing_fd); 396 phdr->backing_fd = -1; 397 } 398 free(phdr->backing_filename); 399 phdr->backing_filename = NULL; 400 return -1; 401 } 402 403 int _UCD_add_backing_file_at_vaddr(struct UCD_info *ui, 404 unsigned long vaddr, 405 const char *filename) 406 { 407 unsigned i; 408 for (i = 0; i < ui->phdrs_count; i++) 409 { 410 struct coredump_phdr *phdr = &ui->phdrs[i]; 411 if (phdr->p_vaddr != vaddr) 412 continue; 413 /* It seems to match. Add it. */ 414 return _UCD_add_backing_file_at_segment(ui, i, filename); 415 } 416 return -1; 417 } 418