1e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng/* 2e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * Post mortem Dwarf CFI based unwinding on top of regs and stack dumps. 3e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * 4e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * Lots of this code have been borrowed or heavily inspired from parts of 5e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * the libunwind 0.99 code which are (amongst other contributors I may have 6e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * forgotten): 7e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * 8e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * Copyright (C) 2002-2007 Hewlett-Packard Co 9e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * Contributed by David Mosberger-Tang <davidm@hpl.hp.com> 10e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * 11e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * And the bugs have been added by: 12e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * 13e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * Copyright (C) 2010, Frederic Weisbecker <fweisbec@gmail.com> 14e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * Copyright (C) 2012, Jiri Olsa <jolsa@redhat.com> 15e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * 16e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng */ 17e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 18e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include <elf.h> 19e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include <gelf.h> 20e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include <fcntl.h> 21e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include <string.h> 22e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include <unistd.h> 23e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include <sys/mman.h> 24e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include <linux/list.h> 25e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include <libunwind.h> 26e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include <libunwind-ptrace.h> 27e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "thread.h" 28e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "session.h" 29e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "perf_regs.h" 30e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "unwind.h" 31e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "util.h" 32e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 33e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengextern int 34e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen ChengUNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as, 35e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng unw_word_t ip, 36e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng unw_dyn_info_t *di, 37e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng unw_proc_info_t *pi, 38e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng int need_unwind_info, void *arg); 39e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 40e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table) 41e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 42e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#define DW_EH_PE_FORMAT_MASK 0x0f /* format of the encoded value */ 43e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#define DW_EH_PE_APPL_MASK 0x70 /* how the value is to be applied */ 44e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 45e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng/* Pointer-encoding formats: */ 46e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#define DW_EH_PE_omit 0xff 47e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#define DW_EH_PE_ptr 0x00 /* pointer-sized unsigned value */ 48e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#define DW_EH_PE_udata4 0x03 /* unsigned 32-bit value */ 49e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#define DW_EH_PE_udata8 0x04 /* unsigned 64-bit value */ 50e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#define DW_EH_PE_sdata4 0x0b /* signed 32-bit value */ 51e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#define DW_EH_PE_sdata8 0x0c /* signed 64-bit value */ 52e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 53e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng/* Pointer-encoding application: */ 54e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#define DW_EH_PE_absptr 0x00 /* absolute value */ 55e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#define DW_EH_PE_pcrel 0x10 /* rel. to addr. of encoded value */ 56e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 57e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng/* 58e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * The following are not documented by LSB v1.3, yet they are used by 59e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * GCC, presumably they aren't documented by LSB since they aren't 60e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * used on Linux: 61e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng */ 62e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#define DW_EH_PE_funcrel 0x40 /* start-of-procedure-relative */ 63e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#define DW_EH_PE_aligned 0x50 /* aligned pointer */ 64e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 65e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng/* Flags intentionaly not handled, since they're not needed: 66e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * #define DW_EH_PE_indirect 0x80 67e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * #define DW_EH_PE_uleb128 0x01 68e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * #define DW_EH_PE_udata2 0x02 69e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * #define DW_EH_PE_sleb128 0x09 70e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * #define DW_EH_PE_sdata2 0x0a 71e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * #define DW_EH_PE_textrel 0x20 72e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * #define DW_EH_PE_datarel 0x30 73e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng */ 74e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 75e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstruct unwind_info { 76e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng struct perf_sample *sample; 77e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng struct machine *machine; 78e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng struct thread *thread; 79e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng u64 sample_uregs; 80e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}; 81e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 82e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#define dw_read(ptr, type, end) ({ \ 83e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng type *__p = (type *) ptr; \ 84e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng type __v; \ 85e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if ((__p + 1) > (type *) end) \ 86e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return -EINVAL; \ 87e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng __v = *__p++; \ 88e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ptr = (typeof(ptr)) __p; \ 89e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng __v; \ 90e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng }) 91e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 92e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int __dw_read_encoded_value(u8 **p, u8 *end, u64 *val, 93e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng u8 encoding) 94e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 95e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng u8 *cur = *p; 96e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng *val = 0; 97e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 98e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng switch (encoding) { 99e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng case DW_EH_PE_omit: 100e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng *val = 0; 101e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng goto out; 102e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng case DW_EH_PE_ptr: 103e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng *val = dw_read(cur, unsigned long, end); 104e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng goto out; 105e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng default: 106e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng break; 107e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 108e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 109e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng switch (encoding & DW_EH_PE_APPL_MASK) { 110e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng case DW_EH_PE_absptr: 111e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng break; 112e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng case DW_EH_PE_pcrel: 113e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng *val = (unsigned long) cur; 114e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng break; 115e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng default: 116e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return -EINVAL; 117e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 118e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 119e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if ((encoding & 0x07) == 0x00) 120e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng encoding |= DW_EH_PE_udata4; 121e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 122e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng switch (encoding & DW_EH_PE_FORMAT_MASK) { 123e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng case DW_EH_PE_sdata4: 124e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng *val += dw_read(cur, s32, end); 125e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng break; 126e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng case DW_EH_PE_udata4: 127e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng *val += dw_read(cur, u32, end); 128e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng break; 129e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng case DW_EH_PE_sdata8: 130e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng *val += dw_read(cur, s64, end); 131e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng break; 132e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng case DW_EH_PE_udata8: 133e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng *val += dw_read(cur, u64, end); 134e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng break; 135e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng default: 136e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return -EINVAL; 137e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 138e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 139e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng out: 140e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng *p = cur; 141e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return 0; 142e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 143e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 144e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#define dw_read_encoded_value(ptr, end, enc) ({ \ 145e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng u64 __v; \ 146e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (__dw_read_encoded_value(&ptr, end, &__v, enc)) { \ 147e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return -EINVAL; \ 148e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } \ 149e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng __v; \ 150e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng }) 151e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 152e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, 153e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng GElf_Shdr *shp, const char *name) 154e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 155e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng Elf_Scn *sec = NULL; 156e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 157e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng while ((sec = elf_nextscn(elf, sec)) != NULL) { 158e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng char *str; 159e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 160e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng gelf_getshdr(sec, shp); 161e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name); 162e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (!strcmp(name, str)) 163e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng break; 164e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 165e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 166e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return sec; 167e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 168e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 169e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic u64 elf_section_offset(int fd, const char *name) 170e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 171e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng Elf *elf; 172e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng GElf_Ehdr ehdr; 173e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng GElf_Shdr shdr; 174e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng u64 offset = 0; 175e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 176e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 177e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (elf == NULL) 178e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return 0; 179e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 180e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng do { 181e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (gelf_getehdr(elf, &ehdr) == NULL) 182e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng break; 183e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 184e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (!elf_section_by_name(elf, &ehdr, &shdr, name)) 185e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng break; 186e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 187e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng offset = shdr.sh_offset; 188e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } while (0); 189e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 190e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng elf_end(elf); 191e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return offset; 192e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 193e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 194e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstruct table_entry { 195e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng u32 start_ip_offset; 196e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng u32 fde_offset; 197e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}; 198e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 199e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstruct eh_frame_hdr { 200e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng unsigned char version; 201e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng unsigned char eh_frame_ptr_enc; 202e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng unsigned char fde_count_enc; 203e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng unsigned char table_enc; 204e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 205e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng /* 206e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * The rest of the header is variable-length and consists of the 207e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * following members: 208e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * 209e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * encoded_t eh_frame_ptr; 210e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * encoded_t fde_count; 211e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng */ 212e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 213e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng /* A single encoded pointer should not be more than 8 bytes. */ 214e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng u64 enc[2]; 215e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 216e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng /* 217e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * struct { 218e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * encoded_t start_ip; 219e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * encoded_t fde_addr; 220e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * } binary_search_table[fde_count]; 221e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng */ 222e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng char data[0]; 223e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} __packed; 224e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 225e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int unwind_spec_ehframe(struct dso *dso, struct machine *machine, 226e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng u64 offset, u64 *table_data, u64 *segbase, 227e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng u64 *fde_count) 228e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 229e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng struct eh_frame_hdr hdr; 230e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng u8 *enc = (u8 *) &hdr.enc; 231e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng u8 *end = (u8 *) &hdr.data; 232e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ssize_t r; 233e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 234e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng r = dso__data_read_offset(dso, machine, offset, 235e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng (u8 *) &hdr, sizeof(hdr)); 236e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (r != sizeof(hdr)) 237e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return -EINVAL; 238e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 239e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng /* We dont need eh_frame_ptr, just skip it. */ 240e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng dw_read_encoded_value(enc, end, hdr.eh_frame_ptr_enc); 241e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 242e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng *fde_count = dw_read_encoded_value(enc, end, hdr.fde_count_enc); 243e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng *segbase = offset; 244e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng *table_data = (enc - (u8 *) &hdr) + offset; 245e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return 0; 246e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 247e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 248e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int read_unwind_spec(struct dso *dso, struct machine *machine, 249e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng u64 *table_data, u64 *segbase, u64 *fde_count) 250e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 251e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng int ret = -EINVAL, fd; 252e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng u64 offset; 253e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 254e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng fd = dso__data_fd(dso, machine); 255e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (fd < 0) 256e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return -EINVAL; 257e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 258e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng offset = elf_section_offset(fd, ".eh_frame_hdr"); 259e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng close(fd); 260e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 261e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (offset) 262e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ret = unwind_spec_ehframe(dso, machine, offset, 263e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng table_data, segbase, 264e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng fde_count); 265e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 266e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng /* TODO .debug_frame check if eh_frame_hdr fails */ 267e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return ret; 268e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 269e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 270e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic struct map *find_map(unw_word_t ip, struct unwind_info *ui) 271e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 272e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng struct addr_location al; 273e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 274e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng thread__find_addr_map(ui->thread, ui->machine, PERF_RECORD_MISC_USER, 275e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng MAP__FUNCTION, ip, &al); 276e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return al.map; 277e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 278e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 279e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int 280e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengfind_proc_info(unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi, 281e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng int need_unwind_info, void *arg) 282e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 283e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng struct unwind_info *ui = arg; 284e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng struct map *map; 285e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng unw_dyn_info_t di; 286e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng u64 table_data, segbase, fde_count; 287e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 288e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng map = find_map(ip, ui); 289e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (!map || !map->dso) 290e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return -EINVAL; 291e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 292e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng pr_debug("unwind: find_proc_info dso %s\n", map->dso->name); 293e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 294e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (read_unwind_spec(map->dso, ui->machine, 295e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng &table_data, &segbase, &fde_count)) 296e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return -EINVAL; 297e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 298e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng memset(&di, 0, sizeof(di)); 299e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng di.format = UNW_INFO_FORMAT_REMOTE_TABLE; 300e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng di.start_ip = map->start; 301e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng di.end_ip = map->end; 302e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng di.u.rti.segbase = map->start + segbase; 303e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng di.u.rti.table_data = map->start + table_data; 304e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng di.u.rti.table_len = fde_count * sizeof(struct table_entry) 305e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng / sizeof(unw_word_t); 306e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return dwarf_search_unwind_table(as, ip, &di, pi, 307e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng need_unwind_info, arg); 308e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 309e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 310e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int access_fpreg(unw_addr_space_t __maybe_unused as, 311e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng unw_regnum_t __maybe_unused num, 312e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng unw_fpreg_t __maybe_unused *val, 313e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng int __maybe_unused __write, 314e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng void __maybe_unused *arg) 315e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 316e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng pr_err("unwind: access_fpreg unsupported\n"); 317e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return -UNW_EINVAL; 318e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 319e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 320e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int get_dyn_info_list_addr(unw_addr_space_t __maybe_unused as, 321e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng unw_word_t __maybe_unused *dil_addr, 322e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng void __maybe_unused *arg) 323e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 324e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return -UNW_ENOINFO; 325e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 326e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 327e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int resume(unw_addr_space_t __maybe_unused as, 328e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng unw_cursor_t __maybe_unused *cu, 329e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng void __maybe_unused *arg) 330e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 331e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng pr_err("unwind: resume unsupported\n"); 332e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return -UNW_EINVAL; 333e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 334e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 335e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int 336e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengget_proc_name(unw_addr_space_t __maybe_unused as, 337e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng unw_word_t __maybe_unused addr, 338e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng char __maybe_unused *bufp, size_t __maybe_unused buf_len, 339e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng unw_word_t __maybe_unused *offp, void __maybe_unused *arg) 340e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 341e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng pr_err("unwind: get_proc_name unsupported\n"); 342e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return -UNW_EINVAL; 343e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 344e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 345e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int access_dso_mem(struct unwind_info *ui, unw_word_t addr, 346e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng unw_word_t *data) 347e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 348e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng struct addr_location al; 349e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ssize_t size; 350e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 351e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng thread__find_addr_map(ui->thread, ui->machine, PERF_RECORD_MISC_USER, 352e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng MAP__FUNCTION, addr, &al); 353e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (!al.map) { 354e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng pr_debug("unwind: no map for %lx\n", (unsigned long)addr); 355e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return -1; 356e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 357e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 358e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (!al.map->dso) 359e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return -1; 360e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 361e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng size = dso__data_read_addr(al.map->dso, al.map, ui->machine, 362e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng addr, (u8 *) data, sizeof(*data)); 363e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 364e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return !(size == sizeof(*data)); 365e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 366e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 367e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int reg_value(unw_word_t *valp, struct regs_dump *regs, int id, 368e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng u64 sample_regs) 369e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 370e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng int i, idx = 0; 371e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 372e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (!(sample_regs & (1 << id))) 373e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return -EINVAL; 374e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 375e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng for (i = 0; i < id; i++) { 376e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (sample_regs & (1 << i)) 377e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng idx++; 378e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 379e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 380e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng *valp = regs->regs[idx]; 381e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return 0; 382e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 383e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 384e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int access_mem(unw_addr_space_t __maybe_unused as, 385e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng unw_word_t addr, unw_word_t *valp, 386e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng int __write, void *arg) 387e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 388e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng struct unwind_info *ui = arg; 389e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng struct stack_dump *stack = &ui->sample->user_stack; 390e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng unw_word_t start, end; 391e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng int offset; 392e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng int ret; 393e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 394e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng /* Don't support write, probably not needed. */ 395e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (__write || !stack || !ui->sample->user_regs.regs) { 396e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng *valp = 0; 397e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return 0; 398e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 399e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 400e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ret = reg_value(&start, &ui->sample->user_regs, PERF_REG_SP, 401e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ui->sample_uregs); 402e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (ret) 403e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return ret; 404e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 405e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng end = start + stack->size; 406e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 407e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng /* Check overflow. */ 408e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (addr + sizeof(unw_word_t) < addr) 409e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return -EINVAL; 410e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 411e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (addr < start || addr + sizeof(unw_word_t) >= end) { 412e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ret = access_dso_mem(ui, addr, valp); 413e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (ret) { 414e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng pr_debug("unwind: access_mem %p not inside range %p-%p\n", 415e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng (void *)addr, (void *)start, (void *)end); 416e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng *valp = 0; 417e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return ret; 418e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 419e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return 0; 420e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 421e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 422e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng offset = addr - start; 423e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng *valp = *(unw_word_t *)&stack->data[offset]; 424e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng pr_debug("unwind: access_mem addr %p, val %lx, offset %d\n", 425e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng (void *)addr, (unsigned long)*valp, offset); 426e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return 0; 427e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 428e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 429e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int access_reg(unw_addr_space_t __maybe_unused as, 430e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng unw_regnum_t regnum, unw_word_t *valp, 431e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng int __write, void *arg) 432e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 433e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng struct unwind_info *ui = arg; 434e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng int id, ret; 435e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 436e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng /* Don't support write, I suspect we don't need it. */ 437e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (__write) { 438e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng pr_err("unwind: access_reg w %d\n", regnum); 439e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return 0; 440e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 441e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 442e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (!ui->sample->user_regs.regs) { 443e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng *valp = 0; 444e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return 0; 445e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 446e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 447e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng id = unwind__arch_reg_id(regnum); 448e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (id < 0) 449e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return -EINVAL; 450e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 451e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ret = reg_value(valp, &ui->sample->user_regs, id, ui->sample_uregs); 452e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (ret) { 453e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng pr_err("unwind: can't read reg %d\n", regnum); 454e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return ret; 455e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 456e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 457e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng pr_debug("unwind: reg %d, val %lx\n", regnum, (unsigned long)*valp); 458e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return 0; 459e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 460e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 461e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic void put_unwind_info(unw_addr_space_t __maybe_unused as, 462e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng unw_proc_info_t *pi __maybe_unused, 463e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng void *arg __maybe_unused) 464e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 465e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng pr_debug("unwind: put_unwind_info called\n"); 466e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 467e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 468e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int entry(u64 ip, struct thread *thread, struct machine *machine, 469e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng unwind_entry_cb_t cb, void *arg) 470e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 471e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng struct unwind_entry e; 472e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng struct addr_location al; 473e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 474e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng thread__find_addr_location(thread, machine, 475e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng PERF_RECORD_MISC_USER, 476e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng MAP__FUNCTION, ip, &al); 477e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 478e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng e.ip = ip; 479e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng e.map = al.map; 480e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng e.sym = al.sym; 481e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 482e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng pr_debug("unwind: %s:ip = 0x%" PRIx64 " (0x%" PRIx64 ")\n", 483e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng al.sym ? al.sym->name : "''", 484e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ip, 485e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng al.map ? al.map->map_ip(al.map, ip) : (u64) 0); 486e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 487e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return cb(&e, arg); 488e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 489e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 490e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic void display_error(int err) 491e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 492e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng switch (err) { 493e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng case UNW_EINVAL: 494e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng pr_err("unwind: Only supports local.\n"); 495e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng break; 496e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng case UNW_EUNSPEC: 497e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng pr_err("unwind: Unspecified error.\n"); 498e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng break; 499e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng case UNW_EBADREG: 500e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng pr_err("unwind: Register unavailable.\n"); 501e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng break; 502e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng default: 503e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng break; 504e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 505e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 506e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 507e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic unw_accessors_t accessors = { 508e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng .find_proc_info = find_proc_info, 509e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng .put_unwind_info = put_unwind_info, 510e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng .get_dyn_info_list_addr = get_dyn_info_list_addr, 511e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng .access_mem = access_mem, 512e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng .access_reg = access_reg, 513e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng .access_fpreg = access_fpreg, 514e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng .resume = resume, 515e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng .get_proc_name = get_proc_name, 516e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}; 517e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 518e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb, 519e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng void *arg) 520e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 521e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng unw_addr_space_t addr_space; 522e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng unw_cursor_t c; 523e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng int ret; 524e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 525e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng addr_space = unw_create_addr_space(&accessors, 0); 526e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (!addr_space) { 527e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng pr_err("unwind: Can't create unwind address space.\n"); 528e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return -ENOMEM; 529e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 530e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 531e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ret = unw_init_remote(&c, addr_space, ui); 532e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (ret) 533e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng display_error(ret); 534e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 535e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng while (!ret && (unw_step(&c) > 0)) { 536e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng unw_word_t ip; 537e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 538e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng unw_get_reg(&c, UNW_REG_IP, &ip); 539e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ret = entry(ip, ui->thread, ui->machine, cb, arg); 540e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 541e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 542e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng unw_destroy_addr_space(addr_space); 543e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return ret; 544e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 545e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 546e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengint unwind__get_entries(unwind_entry_cb_t cb, void *arg, 547e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng struct machine *machine, struct thread *thread, 548e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng u64 sample_uregs, struct perf_sample *data) 549e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 550e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng unw_word_t ip; 551e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng struct unwind_info ui = { 552e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng .sample = data, 553e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng .sample_uregs = sample_uregs, 554e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng .thread = thread, 555e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng .machine = machine, 556e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng }; 557e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng int ret; 558e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 559e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (!data->user_regs.regs) 560e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return -EINVAL; 561e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 562e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ret = reg_value(&ip, &data->user_regs, PERF_REG_IP, sample_uregs); 563e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (ret) 564e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return ret; 565e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 566e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ret = entry(ip, thread, machine, cb, arg); 567e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (ret) 568e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return -ENOMEM; 569e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 570e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return get_entries(&ui, cb, arg); 571e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 572