1 /* libunwind - a platform-independent unwind library
3 This file is part of libunwind.
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:
13 The above copyright notice and this permission notice shall be
14 included in all copies or substantial portions of the Software.
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. */
28 /* Endian detection */
30 #if defined(HAVE_BYTESWAP_H)
33 #if defined(HAVE_ENDIAN_H)
35 #elif defined(HAVE_SYS_ENDIAN_H)
36 # include <sys/endian.h>
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
60 # error "Can't determine endianness"
64 #include <sys/procfs.h> /* struct elf_prstatus */
67 #include "_UCD_internal.h"
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)))
76 _UCD_create(const char *filename
)
83 #define elf_header32 elf_header.h32
84 #define elf_header64 elf_header.h64
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;
91 ui
->edi
.ktab
.format
= -1;
94 int fd
= ui
->coredump_fd
= open(filename
, O_RDONLY
);
97 ui
->coredump_filename
= strdup(filename
);
99 /* No sane ELF32 file is going to be smaller then ELF64 _header_,
100 * so let's just read 64-bit sized one.
102 if (read(fd
, &elf_header64
, sizeof(elf_header64
)) != sizeof(elf_header64
))
104 Debug(0, "'%s' is not an ELF file\n", filename
);
108 if (memcmp(&elf_header32
, ELFMAG
, SELFMAG
) != 0)
110 Debug(0, "'%s' is not an ELF file\n", filename
);
114 if (elf_header32
.e_ident
[EI_CLASS
] != ELFCLASS32
115 && elf_header32
.e_ident
[EI_CLASS
] != ELFCLASS64
)
117 Debug(0, "'%s' is not a 32/64 bit ELF file\n", filename
);
121 if (WE_ARE_LITTLE_ENDIAN
!= (elf_header32
.e_ident
[EI_DATA
] == ELFDATA2LSB
))
123 Debug(0, "'%s' is endian-incompatible\n", filename
);
127 _64bits
= (elf_header32
.e_ident
[EI_CLASS
] == ELFCLASS64
);
128 if (_64bits
&& sizeof(elf_header64
.e_entry
) > sizeof(off_t
))
130 Debug(0, "Can't process '%s': 64-bit file "
131 "while only %ld bits are supported",
132 filename
, 8L * sizeof(off_t
));
138 ? 0 /* todo: (elf_header64.e_ehsize != NN || elf_header64.e_phentsize != NN) */
139 : (elf_header32
.e_ehsize
!= 52 || elf_header32
.e_phentsize
!= 32)
142 Debug(0, "'%s' has wrong e_ehsize or e_phentsize\n", filename
);
146 off_t ofs
= (_64bits
? elf_header64
.e_phoff
: elf_header32
.e_phoff
);
147 if (lseek(fd
, ofs
, SEEK_SET
) != ofs
)
149 Debug(0, "Can't read phdrs from '%s'\n", filename
);
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]));
156 coredump_phdr_t
*cur
= phdrs
;
161 if (read(fd
, &hdr64
, sizeof(hdr64
)) != sizeof(hdr64
))
163 Debug(0, "Can't read phdrs from '%s'\n", filename
);
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
;
182 coredump_phdr_t
*cur
= phdrs
;
187 if (read(fd
, &hdr32
, sizeof(hdr32
)) != sizeof(hdr32
))
189 Debug(0, "Can't read phdrs from '%s'\n", filename
);
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
;
209 coredump_phdr_t
*cur
= phdrs
;
212 Debug(2, "phdr[%03d]: type:%d", i
, cur
->p_type
);
213 if (cur
->p_type
== PT_NOTE
)
215 Elf32_Nhdr
*note_hdr
, *note_end
;
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
)
222 Debug(0, "Can't read PT_NOTE from '%s'\n", filename
);
226 note_end
= STRUCT_MEMBER_P (ui
->note_phdr
, cur
->p_filesz
);
228 /* Count number of threads */
230 note_hdr
= (Elf32_Nhdr
*)ui
->note_phdr
;
231 while (NOTE_FITS (note_hdr
, note_end
))
233 if (note_hdr
->n_type
== NT_PRSTATUS
)
236 note_hdr
= NOTE_NEXT (note_hdr
);
239 ui
->n_threads
= n_threads
;
240 ui
->threads
= malloc(sizeof (void *) * n_threads
);
243 note_hdr
= (Elf32_Nhdr
*)ui
->note_phdr
;
244 while (NOTE_FITS (note_hdr
, note_end
))
246 if (note_hdr
->n_type
== NT_PRSTATUS
)
247 ui
->threads
[n_threads
++] = NOTE_DATA (note_hdr
);
249 note_hdr
= NOTE_NEXT (note_hdr
);
252 if (cur
->p_type
== PT_LOAD
)
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
,
261 if (cur
->p_filesz
< cur
->p_memsz
)
262 Debug(2, " partial");
263 if (cur
->p_flags
& PF_X
)
264 Debug(2, " executable");
271 if (ui
->n_threads
== 0)
273 Debug(0, "No NT_PRSTATUS note found in '%s'\n", filename
);
277 ui
->prstatus
= ui
->threads
[0];
286 int _UCD_get_num_threads(struct UCD_info
*ui
)
288 return ui
->n_threads
;
291 void _UCD_select_thread(struct UCD_info
*ui
, int n
)
293 if (n
>= 0 && n
< ui
->n_threads
)
294 ui
->prstatus
= ui
->threads
[n
];
297 pid_t
_UCD_get_pid(struct UCD_info
*ui
)
299 return ui
->prstatus
->pr_pid
;
302 int _UCD_get_cursig(struct UCD_info
*ui
)
304 return ui
->prstatus
->pr_cursig
;
307 int _UCD_add_backing_file_at_segment(struct UCD_info
*ui
, int phdr_no
, const char *filename
)
309 if ((unsigned)phdr_no
>= ui
->phdrs_count
)
311 Debug(0, "There is no segment %d in this coredump\n", phdr_no
);
315 struct coredump_phdr
*phdr
= &ui
->phdrs
[phdr_no
];
316 if (phdr
->backing_filename
)
318 Debug(0, "Backing file already added to segment %d\n", phdr_no
);
322 int fd
= open(filename
, O_RDONLY
);
325 Debug(0, "Can't open '%s'\n", filename
);
329 phdr
->backing_fd
= fd
;
330 phdr
->backing_filename
= strdup(filename
);
333 if (fstat(fd
, &statbuf
) != 0)
335 Debug(0, "Can't stat '%s'\n", filename
);
338 phdr
->backing_filesize
= (uoff_t
)statbuf
.st_size
;
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
);
343 if (phdr
->backing_filesize
> phdr
->p_memsz
)
345 /* This is expected */
346 Debug(2, "Note: phdr[%u] is %lld bytes, file is larger: %lld bytes\n",
348 (unsigned long long)phdr
->p_memsz
,
349 (unsigned long long)phdr
->backing_filesize
352 //TODO: else loudly complain? Maybe even fail?
354 if (phdr
->p_filesz
!= 0)
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
363 Debug(0, "Error reading from coredump file\n");
369 if ((uoff_t
)read(fd
, file_buf
, phdr
->p_filesz
) != phdr
->p_filesz
)
371 Debug(0, "Error reading from '%s'\n", filename
);
374 int r
= memcmp(core_buf
, file_buf
, phdr
->p_filesz
);
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
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
393 if (phdr
->backing_fd
>= 0)
395 close(phdr
->backing_fd
);
396 phdr
->backing_fd
= -1;
398 free(phdr
->backing_filename
);
399 phdr
->backing_filename
= NULL
;
403 int _UCD_add_backing_file_at_vaddr(struct UCD_info
*ui
,
405 const char *filename
)
408 for (i
= 0; i
< ui
->phdrs_count
; i
++)
410 struct coredump_phdr
*phdr
= &ui
->phdrs
[i
];
411 if (phdr
->p_vaddr
!= vaddr
)
413 /* It seems to match. Add it. */
414 return _UCD_add_backing_file_at_segment(ui
, i
, filename
);