1 /* Get Dwarf Frame state for target core file. 2 Copyright (C) 2013, 2014 Red Hat, Inc. 3 This file is part of elfutils. 4 5 This file is free software; you can redistribute it and/or modify 6 it under the terms of either 7 8 * the GNU Lesser General Public License as published by the Free 9 Software Foundation; either version 3 of the License, or (at 10 your option) any later version 11 12 or 13 14 * the GNU General Public License as published by the Free 15 Software Foundation; either version 2 of the License, or (at 16 your option) any later version 17 18 or both in parallel, as here. 19 20 elfutils is distributed in the hope that it will be useful, but 21 WITHOUT ANY WARRANTY; without even the implied warranty of 22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 23 General Public License for more details. 24 25 You should have received copies of the GNU General Public License and 26 the GNU Lesser General Public License along with this program. If 27 not, see <http://www.gnu.org/licenses/>. */ 28 29 #include "libdwflP.h" 30 #include <fcntl.h> 31 #include "system.h" 32 33 #include "../libdw/memory-access.h" 34 35 #ifndef MIN 36 # define MIN(a, b) ((a) < (b) ? (a) : (b)) 37 #endif 38 39 struct core_arg 40 { 41 Elf *core; 42 Elf_Data *note_data; 43 size_t thread_note_offset; 44 Ebl *ebl; 45 }; 46 47 struct thread_arg 48 { 49 struct core_arg *core_arg; 50 size_t note_offset; 51 }; 52 53 static bool 54 core_memory_read (Dwfl *dwfl, Dwarf_Addr addr, Dwarf_Word *result, 55 void *dwfl_arg) 56 { 57 Dwfl_Process *process = dwfl->process; 58 struct core_arg *core_arg = dwfl_arg; 59 Elf *core = core_arg->core; 60 assert (core != NULL); 61 static size_t phnum; 62 if (elf_getphdrnum (core, &phnum) < 0) 63 { 64 __libdwfl_seterrno (DWFL_E_LIBELF); 65 return false; 66 } 67 for (size_t cnt = 0; cnt < phnum; ++cnt) 68 { 69 GElf_Phdr phdr_mem, *phdr = gelf_getphdr (core, cnt, &phdr_mem); 70 if (phdr == NULL || phdr->p_type != PT_LOAD) 71 continue; 72 /* Bias is zero here, a core file itself has no bias. */ 73 GElf_Addr start = __libdwfl_segment_start (dwfl, phdr->p_vaddr); 74 GElf_Addr end = __libdwfl_segment_end (dwfl, 75 phdr->p_vaddr + phdr->p_memsz); 76 unsigned bytes = ebl_get_elfclass (process->ebl) == ELFCLASS64 ? 8 : 4; 77 if (addr < start || addr + bytes > end) 78 continue; 79 Elf_Data *data; 80 data = elf_getdata_rawchunk (core, phdr->p_offset + addr - start, 81 bytes, ELF_T_ADDR); 82 if (data == NULL) 83 { 84 __libdwfl_seterrno (DWFL_E_LIBELF); 85 return false; 86 } 87 assert (data->d_size == bytes); 88 if (bytes == 8) 89 *result = read_8ubyte_unaligned_noncvt (data->d_buf); 90 else 91 *result = read_4ubyte_unaligned_noncvt (data->d_buf); 92 return true; 93 } 94 __libdwfl_seterrno (DWFL_E_ADDR_OUTOFRANGE); 95 return false; 96 } 97 98 static pid_t 99 core_next_thread (Dwfl *dwfl __attribute__ ((unused)), void *dwfl_arg, 100 void **thread_argp) 101 { 102 struct core_arg *core_arg = dwfl_arg; 103 Elf *core = core_arg->core; 104 GElf_Nhdr nhdr; 105 size_t name_offset; 106 size_t desc_offset; 107 Elf_Data *note_data = core_arg->note_data; 108 size_t offset; 109 110 struct thread_arg *thread_arg; 111 if (*thread_argp == NULL) 112 { 113 core_arg->thread_note_offset = 0; 114 thread_arg = malloc (sizeof (*thread_arg)); 115 if (thread_arg == NULL) 116 { 117 __libdwfl_seterrno (DWFL_E_NOMEM); 118 return -1; 119 } 120 thread_arg->core_arg = core_arg; 121 *thread_argp = thread_arg; 122 } 123 else 124 thread_arg = (struct thread_arg *) *thread_argp; 125 126 while (offset = core_arg->thread_note_offset, offset < note_data->d_size 127 && (core_arg->thread_note_offset = gelf_getnote (note_data, offset, 128 &nhdr, &name_offset, 129 &desc_offset)) > 0) 130 { 131 /* Do not check NAME for now, help broken Linux kernels. */ 132 const char *name = note_data->d_buf + name_offset; 133 const char *desc = note_data->d_buf + desc_offset; 134 GElf_Word regs_offset; 135 size_t nregloc; 136 const Ebl_Register_Location *reglocs; 137 size_t nitems; 138 const Ebl_Core_Item *items; 139 if (! ebl_core_note (core_arg->ebl, &nhdr, name, 140 ®s_offset, &nregloc, ®locs, &nitems, &items)) 141 { 142 /* This note may be just not recognized, skip it. */ 143 continue; 144 } 145 if (nhdr.n_type != NT_PRSTATUS) 146 continue; 147 const Ebl_Core_Item *item; 148 for (item = items; item < items + nitems; item++) 149 if (strcmp (item->name, "pid") == 0) 150 break; 151 if (item == items + nitems) 152 continue; 153 uint32_t val32 = read_4ubyte_unaligned_noncvt (desc + item->offset); 154 val32 = (elf_getident (core, NULL)[EI_DATA] == ELFDATA2MSB 155 ? be32toh (val32) : le32toh (val32)); 156 pid_t tid = (int32_t) val32; 157 eu_static_assert (sizeof val32 <= sizeof tid); 158 thread_arg->note_offset = offset; 159 return tid; 160 } 161 162 free (thread_arg); 163 return 0; 164 } 165 166 static bool 167 core_set_initial_registers (Dwfl_Thread *thread, void *thread_arg_voidp) 168 { 169 struct thread_arg *thread_arg = thread_arg_voidp; 170 struct core_arg *core_arg = thread_arg->core_arg; 171 Elf *core = core_arg->core; 172 size_t offset = thread_arg->note_offset; 173 GElf_Nhdr nhdr; 174 size_t name_offset; 175 size_t desc_offset; 176 Elf_Data *note_data = core_arg->note_data; 177 size_t nregs = ebl_frame_nregs (core_arg->ebl); 178 assert (nregs > 0); 179 assert (offset < note_data->d_size); 180 size_t getnote_err = gelf_getnote (note_data, offset, &nhdr, &name_offset, 181 &desc_offset); 182 /* __libdwfl_attach_state_for_core already verified the note is there. */ 183 assert (getnote_err != 0); 184 /* Do not check NAME for now, help broken Linux kernels. */ 185 const char *name = note_data->d_buf + name_offset; 186 const char *desc = note_data->d_buf + desc_offset; 187 GElf_Word regs_offset; 188 size_t nregloc; 189 const Ebl_Register_Location *reglocs; 190 size_t nitems; 191 const Ebl_Core_Item *items; 192 int core_note_err = ebl_core_note (core_arg->ebl, &nhdr, name, ®s_offset, 193 &nregloc, ®locs, &nitems, &items); 194 /* __libdwfl_attach_state_for_core already verified the note is there. */ 195 assert (core_note_err != 0); 196 assert (nhdr.n_type == NT_PRSTATUS); 197 const Ebl_Core_Item *item; 198 for (item = items; item < items + nitems; item++) 199 if (strcmp (item->name, "pid") == 0) 200 break; 201 assert (item < items + nitems); 202 pid_t tid; 203 { 204 uint32_t val32 = read_4ubyte_unaligned_noncvt (desc + item->offset); 205 val32 = (elf_getident (core, NULL)[EI_DATA] == ELFDATA2MSB 206 ? be32toh (val32) : le32toh (val32)); 207 tid = (int32_t) val32; 208 eu_static_assert (sizeof val32 <= sizeof tid); 209 } 210 /* core_next_thread already found this TID there. */ 211 assert (tid == INTUSE(dwfl_thread_tid) (thread)); 212 for (item = items; item < items + nitems; item++) 213 if (item->pc_register) 214 break; 215 if (item < items + nitems) 216 { 217 Dwarf_Word pc; 218 switch (gelf_getclass (core) == ELFCLASS32 ? 32 : 64) 219 { 220 case 32:; 221 uint32_t val32 = read_4ubyte_unaligned_noncvt (desc + item->offset); 222 val32 = (elf_getident (core, NULL)[EI_DATA] == ELFDATA2MSB 223 ? be32toh (val32) : le32toh (val32)); 224 /* Do a host width conversion. */ 225 pc = val32; 226 break; 227 case 64:; 228 uint64_t val64 = read_8ubyte_unaligned_noncvt (desc + item->offset); 229 val64 = (elf_getident (core, NULL)[EI_DATA] == ELFDATA2MSB 230 ? be64toh (val64) : le64toh (val64)); 231 pc = val64; 232 break; 233 default: 234 abort (); 235 } 236 INTUSE(dwfl_thread_state_register_pc) (thread, pc); 237 } 238 desc += regs_offset; 239 for (size_t regloci = 0; regloci < nregloc; regloci++) 240 { 241 const Ebl_Register_Location *regloc = reglocs + regloci; 242 // Iterate even regs out of NREGS range so that we can find pc_register. 243 if (regloc->bits != 32 && regloc->bits != 64) 244 continue; 245 const char *reg_desc = desc + regloc->offset; 246 for (unsigned regno = regloc->regno; 247 regno < regloc->regno + (regloc->count ?: 1U); 248 regno++) 249 { 250 /* PPC provides DWARF register 65 irrelevant for 251 CFI which clashes with register 108 (LR) we need. 252 LR (108) is provided earlier (in NT_PRSTATUS) than the # 65. 253 FIXME: It depends now on their order in core notes. 254 FIXME: It uses private function. */ 255 if (regno < nregs 256 && __libdwfl_frame_reg_get (thread->unwound, regno, NULL)) 257 continue; 258 Dwarf_Word val; 259 switch (regloc->bits) 260 { 261 case 32:; 262 uint32_t val32 = read_4ubyte_unaligned_noncvt (reg_desc); 263 reg_desc += sizeof val32; 264 val32 = (elf_getident (core, NULL)[EI_DATA] == ELFDATA2MSB 265 ? be32toh (val32) : le32toh (val32)); 266 /* Do a host width conversion. */ 267 val = val32; 268 break; 269 case 64:; 270 uint64_t val64 = read_8ubyte_unaligned_noncvt (reg_desc); 271 reg_desc += sizeof val64; 272 val64 = (elf_getident (core, NULL)[EI_DATA] == ELFDATA2MSB 273 ? be64toh (val64) : le64toh (val64)); 274 assert (sizeof (*thread->unwound->regs) == sizeof val64); 275 val = val64; 276 break; 277 default: 278 abort (); 279 } 280 /* Registers not valid for CFI are just ignored. */ 281 if (regno < nregs) 282 INTUSE(dwfl_thread_state_registers) (thread, regno, 1, &val); 283 if (regloc->pc_register) 284 INTUSE(dwfl_thread_state_register_pc) (thread, val); 285 reg_desc += regloc->pad; 286 } 287 } 288 return true; 289 } 290 291 static void 292 core_detach (Dwfl *dwfl __attribute__ ((unused)), void *dwfl_arg) 293 { 294 struct core_arg *core_arg = dwfl_arg; 295 ebl_closebackend (core_arg->ebl); 296 free (core_arg); 297 } 298 299 static const Dwfl_Thread_Callbacks core_thread_callbacks = 300 { 301 core_next_thread, 302 NULL, /* get_thread */ 303 core_memory_read, 304 core_set_initial_registers, 305 core_detach, 306 NULL, /* core_thread_detach */ 307 }; 308 309 int 310 dwfl_core_file_attach (Dwfl *dwfl, Elf *core) 311 { 312 Dwfl_Error err = DWFL_E_NOERROR; 313 Ebl *ebl = ebl_openbackend (core); 314 if (ebl == NULL) 315 { 316 err = DWFL_E_LIBEBL; 317 fail_err: 318 if (dwfl->process == NULL && dwfl->attacherr == DWFL_E_NOERROR) 319 dwfl->attacherr = __libdwfl_canon_error (err); 320 __libdwfl_seterrno (err); 321 return -1; 322 } 323 size_t nregs = ebl_frame_nregs (ebl); 324 if (nregs == 0) 325 { 326 err = DWFL_E_NO_UNWIND; 327 fail: 328 ebl_closebackend (ebl); 329 goto fail_err; 330 } 331 GElf_Ehdr ehdr_mem, *ehdr = gelf_getehdr (core, &ehdr_mem); 332 if (ehdr == NULL) 333 { 334 err = DWFL_E_LIBELF; 335 goto fail; 336 } 337 if (ehdr->e_type != ET_CORE) 338 { 339 err = DWFL_E_NO_CORE_FILE; 340 goto fail; 341 } 342 size_t phnum; 343 if (elf_getphdrnum (core, &phnum) < 0) 344 { 345 err = DWFL_E_LIBELF; 346 goto fail; 347 } 348 pid_t pid = -1; 349 Elf_Data *note_data = NULL; 350 for (size_t cnt = 0; cnt < phnum; ++cnt) 351 { 352 GElf_Phdr phdr_mem, *phdr = gelf_getphdr (core, cnt, &phdr_mem); 353 if (phdr != NULL && phdr->p_type == PT_NOTE) 354 { 355 note_data = elf_getdata_rawchunk (core, phdr->p_offset, 356 phdr->p_filesz, ELF_T_NHDR); 357 break; 358 } 359 } 360 if (note_data == NULL) 361 { 362 err = DWFL_E_LIBELF; 363 goto fail; 364 } 365 size_t offset = 0; 366 GElf_Nhdr nhdr; 367 size_t name_offset; 368 size_t desc_offset; 369 while (offset < note_data->d_size 370 && (offset = gelf_getnote (note_data, offset, 371 &nhdr, &name_offset, &desc_offset)) > 0) 372 { 373 /* Do not check NAME for now, help broken Linux kernels. */ 374 const char *name = note_data->d_buf + name_offset; 375 const char *desc = note_data->d_buf + desc_offset; 376 GElf_Word regs_offset; 377 size_t nregloc; 378 const Ebl_Register_Location *reglocs; 379 size_t nitems; 380 const Ebl_Core_Item *items; 381 if (! ebl_core_note (ebl, &nhdr, name, 382 ®s_offset, &nregloc, ®locs, &nitems, &items)) 383 { 384 /* This note may be just not recognized, skip it. */ 385 continue; 386 } 387 if (nhdr.n_type != NT_PRPSINFO) 388 continue; 389 const Ebl_Core_Item *item; 390 for (item = items; item < items + nitems; item++) 391 if (strcmp (item->name, "pid") == 0) 392 break; 393 if (item == items + nitems) 394 continue; 395 uint32_t val32 = read_4ubyte_unaligned_noncvt (desc + item->offset); 396 val32 = (elf_getident (core, NULL)[EI_DATA] == ELFDATA2MSB 397 ? be32toh (val32) : le32toh (val32)); 398 pid = (int32_t) val32; 399 eu_static_assert (sizeof val32 <= sizeof pid); 400 break; 401 } 402 if (pid == -1) 403 { 404 /* No valid NT_PRPSINFO recognized in this CORE. */ 405 err = DWFL_E_BADELF; 406 goto fail; 407 } 408 struct core_arg *core_arg = malloc (sizeof *core_arg); 409 if (core_arg == NULL) 410 { 411 err = DWFL_E_NOMEM; 412 goto fail; 413 } 414 core_arg->core = core; 415 core_arg->note_data = note_data; 416 core_arg->thread_note_offset = 0; 417 core_arg->ebl = ebl; 418 if (! INTUSE(dwfl_attach_state) (dwfl, core, pid, &core_thread_callbacks, 419 core_arg)) 420 { 421 free (core_arg); 422 ebl_closebackend (ebl); 423 return -1; 424 } 425 return pid; 426 } 427 INTDEF (dwfl_core_file_attach) 428