18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Post mortem Dwarf CFI based unwinding on top of regs and stack dumps. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Lots of this code have been borrowed or heavily inspired from parts of 68c2ecf20Sopenharmony_ci * the libunwind 0.99 code which are (amongst other contributors I may have 78c2ecf20Sopenharmony_ci * forgotten): 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Copyright (C) 2002-2007 Hewlett-Packard Co 108c2ecf20Sopenharmony_ci * Contributed by David Mosberger-Tang <davidm@hpl.hp.com> 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * And the bugs have been added by: 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * Copyright (C) 2010, Frederic Weisbecker <fweisbec@gmail.com> 158c2ecf20Sopenharmony_ci * Copyright (C) 2012, Jiri Olsa <jolsa@redhat.com> 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci */ 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include <elf.h> 208c2ecf20Sopenharmony_ci#include <errno.h> 218c2ecf20Sopenharmony_ci#include <gelf.h> 228c2ecf20Sopenharmony_ci#include <fcntl.h> 238c2ecf20Sopenharmony_ci#include <inttypes.h> 248c2ecf20Sopenharmony_ci#include <string.h> 258c2ecf20Sopenharmony_ci#include <unistd.h> 268c2ecf20Sopenharmony_ci#include <sys/mman.h> 278c2ecf20Sopenharmony_ci#include <linux/list.h> 288c2ecf20Sopenharmony_ci#include <linux/zalloc.h> 298c2ecf20Sopenharmony_ci#ifndef REMOTE_UNWIND_LIBUNWIND 308c2ecf20Sopenharmony_ci#include <libunwind.h> 318c2ecf20Sopenharmony_ci#include <libunwind-ptrace.h> 328c2ecf20Sopenharmony_ci#endif 338c2ecf20Sopenharmony_ci#include "callchain.h" 348c2ecf20Sopenharmony_ci#include "thread.h" 358c2ecf20Sopenharmony_ci#include "session.h" 368c2ecf20Sopenharmony_ci#include "perf_regs.h" 378c2ecf20Sopenharmony_ci#include "unwind.h" 388c2ecf20Sopenharmony_ci#include "map.h" 398c2ecf20Sopenharmony_ci#include "symbol.h" 408c2ecf20Sopenharmony_ci#include "debug.h" 418c2ecf20Sopenharmony_ci#include "asm/bug.h" 428c2ecf20Sopenharmony_ci#include "dso.h" 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ciextern int 458c2ecf20Sopenharmony_ciUNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as, 468c2ecf20Sopenharmony_ci unw_word_t ip, 478c2ecf20Sopenharmony_ci unw_dyn_info_t *di, 488c2ecf20Sopenharmony_ci unw_proc_info_t *pi, 498c2ecf20Sopenharmony_ci int need_unwind_info, void *arg); 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci#define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table) 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ciextern int 548c2ecf20Sopenharmony_ciUNW_OBJ(dwarf_find_debug_frame) (int found, unw_dyn_info_t *di_debug, 558c2ecf20Sopenharmony_ci unw_word_t ip, 568c2ecf20Sopenharmony_ci unw_word_t segbase, 578c2ecf20Sopenharmony_ci const char *obj_name, unw_word_t start, 588c2ecf20Sopenharmony_ci unw_word_t end); 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci#define dwarf_find_debug_frame UNW_OBJ(dwarf_find_debug_frame) 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci#define DW_EH_PE_FORMAT_MASK 0x0f /* format of the encoded value */ 638c2ecf20Sopenharmony_ci#define DW_EH_PE_APPL_MASK 0x70 /* how the value is to be applied */ 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci/* Pointer-encoding formats: */ 668c2ecf20Sopenharmony_ci#define DW_EH_PE_omit 0xff 678c2ecf20Sopenharmony_ci#define DW_EH_PE_ptr 0x00 /* pointer-sized unsigned value */ 688c2ecf20Sopenharmony_ci#define DW_EH_PE_udata4 0x03 /* unsigned 32-bit value */ 698c2ecf20Sopenharmony_ci#define DW_EH_PE_udata8 0x04 /* unsigned 64-bit value */ 708c2ecf20Sopenharmony_ci#define DW_EH_PE_sdata4 0x0b /* signed 32-bit value */ 718c2ecf20Sopenharmony_ci#define DW_EH_PE_sdata8 0x0c /* signed 64-bit value */ 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci/* Pointer-encoding application: */ 748c2ecf20Sopenharmony_ci#define DW_EH_PE_absptr 0x00 /* absolute value */ 758c2ecf20Sopenharmony_ci#define DW_EH_PE_pcrel 0x10 /* rel. to addr. of encoded value */ 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci/* 788c2ecf20Sopenharmony_ci * The following are not documented by LSB v1.3, yet they are used by 798c2ecf20Sopenharmony_ci * GCC, presumably they aren't documented by LSB since they aren't 808c2ecf20Sopenharmony_ci * used on Linux: 818c2ecf20Sopenharmony_ci */ 828c2ecf20Sopenharmony_ci#define DW_EH_PE_funcrel 0x40 /* start-of-procedure-relative */ 838c2ecf20Sopenharmony_ci#define DW_EH_PE_aligned 0x50 /* aligned pointer */ 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci/* Flags intentionaly not handled, since they're not needed: 868c2ecf20Sopenharmony_ci * #define DW_EH_PE_indirect 0x80 878c2ecf20Sopenharmony_ci * #define DW_EH_PE_uleb128 0x01 888c2ecf20Sopenharmony_ci * #define DW_EH_PE_udata2 0x02 898c2ecf20Sopenharmony_ci * #define DW_EH_PE_sleb128 0x09 908c2ecf20Sopenharmony_ci * #define DW_EH_PE_sdata2 0x0a 918c2ecf20Sopenharmony_ci * #define DW_EH_PE_textrel 0x20 928c2ecf20Sopenharmony_ci * #define DW_EH_PE_datarel 0x30 938c2ecf20Sopenharmony_ci */ 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_cistruct unwind_info { 968c2ecf20Sopenharmony_ci struct perf_sample *sample; 978c2ecf20Sopenharmony_ci struct machine *machine; 988c2ecf20Sopenharmony_ci struct thread *thread; 998c2ecf20Sopenharmony_ci}; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci#define dw_read(ptr, type, end) ({ \ 1028c2ecf20Sopenharmony_ci type *__p = (type *) ptr; \ 1038c2ecf20Sopenharmony_ci type __v; \ 1048c2ecf20Sopenharmony_ci if ((__p + 1) > (type *) end) \ 1058c2ecf20Sopenharmony_ci return -EINVAL; \ 1068c2ecf20Sopenharmony_ci __v = *__p++; \ 1078c2ecf20Sopenharmony_ci ptr = (typeof(ptr)) __p; \ 1088c2ecf20Sopenharmony_ci __v; \ 1098c2ecf20Sopenharmony_ci }) 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_cistatic int __dw_read_encoded_value(u8 **p, u8 *end, u64 *val, 1128c2ecf20Sopenharmony_ci u8 encoding) 1138c2ecf20Sopenharmony_ci{ 1148c2ecf20Sopenharmony_ci u8 *cur = *p; 1158c2ecf20Sopenharmony_ci *val = 0; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci switch (encoding) { 1188c2ecf20Sopenharmony_ci case DW_EH_PE_omit: 1198c2ecf20Sopenharmony_ci *val = 0; 1208c2ecf20Sopenharmony_ci goto out; 1218c2ecf20Sopenharmony_ci case DW_EH_PE_ptr: 1228c2ecf20Sopenharmony_ci *val = dw_read(cur, unsigned long, end); 1238c2ecf20Sopenharmony_ci goto out; 1248c2ecf20Sopenharmony_ci default: 1258c2ecf20Sopenharmony_ci break; 1268c2ecf20Sopenharmony_ci } 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci switch (encoding & DW_EH_PE_APPL_MASK) { 1298c2ecf20Sopenharmony_ci case DW_EH_PE_absptr: 1308c2ecf20Sopenharmony_ci break; 1318c2ecf20Sopenharmony_ci case DW_EH_PE_pcrel: 1328c2ecf20Sopenharmony_ci *val = (unsigned long) cur; 1338c2ecf20Sopenharmony_ci break; 1348c2ecf20Sopenharmony_ci default: 1358c2ecf20Sopenharmony_ci return -EINVAL; 1368c2ecf20Sopenharmony_ci } 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci if ((encoding & 0x07) == 0x00) 1398c2ecf20Sopenharmony_ci encoding |= DW_EH_PE_udata4; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci switch (encoding & DW_EH_PE_FORMAT_MASK) { 1428c2ecf20Sopenharmony_ci case DW_EH_PE_sdata4: 1438c2ecf20Sopenharmony_ci *val += dw_read(cur, s32, end); 1448c2ecf20Sopenharmony_ci break; 1458c2ecf20Sopenharmony_ci case DW_EH_PE_udata4: 1468c2ecf20Sopenharmony_ci *val += dw_read(cur, u32, end); 1478c2ecf20Sopenharmony_ci break; 1488c2ecf20Sopenharmony_ci case DW_EH_PE_sdata8: 1498c2ecf20Sopenharmony_ci *val += dw_read(cur, s64, end); 1508c2ecf20Sopenharmony_ci break; 1518c2ecf20Sopenharmony_ci case DW_EH_PE_udata8: 1528c2ecf20Sopenharmony_ci *val += dw_read(cur, u64, end); 1538c2ecf20Sopenharmony_ci break; 1548c2ecf20Sopenharmony_ci default: 1558c2ecf20Sopenharmony_ci return -EINVAL; 1568c2ecf20Sopenharmony_ci } 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci out: 1598c2ecf20Sopenharmony_ci *p = cur; 1608c2ecf20Sopenharmony_ci return 0; 1618c2ecf20Sopenharmony_ci} 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci#define dw_read_encoded_value(ptr, end, enc) ({ \ 1648c2ecf20Sopenharmony_ci u64 __v; \ 1658c2ecf20Sopenharmony_ci if (__dw_read_encoded_value(&ptr, end, &__v, enc)) { \ 1668c2ecf20Sopenharmony_ci return -EINVAL; \ 1678c2ecf20Sopenharmony_ci } \ 1688c2ecf20Sopenharmony_ci __v; \ 1698c2ecf20Sopenharmony_ci }) 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_cistatic u64 elf_section_offset(int fd, const char *name) 1728c2ecf20Sopenharmony_ci{ 1738c2ecf20Sopenharmony_ci Elf *elf; 1748c2ecf20Sopenharmony_ci GElf_Ehdr ehdr; 1758c2ecf20Sopenharmony_ci GElf_Shdr shdr; 1768c2ecf20Sopenharmony_ci u64 offset = 0; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 1798c2ecf20Sopenharmony_ci if (elf == NULL) 1808c2ecf20Sopenharmony_ci return 0; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci do { 1838c2ecf20Sopenharmony_ci if (gelf_getehdr(elf, &ehdr) == NULL) 1848c2ecf20Sopenharmony_ci break; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci if (!elf_section_by_name(elf, &ehdr, &shdr, name, NULL)) 1878c2ecf20Sopenharmony_ci break; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci offset = shdr.sh_offset; 1908c2ecf20Sopenharmony_ci } while (0); 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci elf_end(elf); 1938c2ecf20Sopenharmony_ci return offset; 1948c2ecf20Sopenharmony_ci} 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci#ifndef NO_LIBUNWIND_DEBUG_FRAME 1978c2ecf20Sopenharmony_cistatic int elf_is_exec(int fd, const char *name) 1988c2ecf20Sopenharmony_ci{ 1998c2ecf20Sopenharmony_ci Elf *elf; 2008c2ecf20Sopenharmony_ci GElf_Ehdr ehdr; 2018c2ecf20Sopenharmony_ci int retval = 0; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 2048c2ecf20Sopenharmony_ci if (elf == NULL) 2058c2ecf20Sopenharmony_ci return 0; 2068c2ecf20Sopenharmony_ci if (gelf_getehdr(elf, &ehdr) == NULL) 2078c2ecf20Sopenharmony_ci goto out; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci retval = (ehdr.e_type == ET_EXEC); 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ciout: 2128c2ecf20Sopenharmony_ci elf_end(elf); 2138c2ecf20Sopenharmony_ci pr_debug("unwind: elf_is_exec(%s): %d\n", name, retval); 2148c2ecf20Sopenharmony_ci return retval; 2158c2ecf20Sopenharmony_ci} 2168c2ecf20Sopenharmony_ci#endif 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_cistruct table_entry { 2198c2ecf20Sopenharmony_ci u32 start_ip_offset; 2208c2ecf20Sopenharmony_ci u32 fde_offset; 2218c2ecf20Sopenharmony_ci}; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_cistruct eh_frame_hdr { 2248c2ecf20Sopenharmony_ci unsigned char version; 2258c2ecf20Sopenharmony_ci unsigned char eh_frame_ptr_enc; 2268c2ecf20Sopenharmony_ci unsigned char fde_count_enc; 2278c2ecf20Sopenharmony_ci unsigned char table_enc; 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci /* 2308c2ecf20Sopenharmony_ci * The rest of the header is variable-length and consists of the 2318c2ecf20Sopenharmony_ci * following members: 2328c2ecf20Sopenharmony_ci * 2338c2ecf20Sopenharmony_ci * encoded_t eh_frame_ptr; 2348c2ecf20Sopenharmony_ci * encoded_t fde_count; 2358c2ecf20Sopenharmony_ci */ 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci /* A single encoded pointer should not be more than 8 bytes. */ 2388c2ecf20Sopenharmony_ci u64 enc[2]; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci /* 2418c2ecf20Sopenharmony_ci * struct { 2428c2ecf20Sopenharmony_ci * encoded_t start_ip; 2438c2ecf20Sopenharmony_ci * encoded_t fde_addr; 2448c2ecf20Sopenharmony_ci * } binary_search_table[fde_count]; 2458c2ecf20Sopenharmony_ci */ 2468c2ecf20Sopenharmony_ci char data[]; 2478c2ecf20Sopenharmony_ci} __packed; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_cistatic int unwind_spec_ehframe(struct dso *dso, struct machine *machine, 2508c2ecf20Sopenharmony_ci u64 offset, u64 *table_data, u64 *segbase, 2518c2ecf20Sopenharmony_ci u64 *fde_count) 2528c2ecf20Sopenharmony_ci{ 2538c2ecf20Sopenharmony_ci struct eh_frame_hdr hdr; 2548c2ecf20Sopenharmony_ci u8 *enc = (u8 *) &hdr.enc; 2558c2ecf20Sopenharmony_ci u8 *end = (u8 *) &hdr.data; 2568c2ecf20Sopenharmony_ci ssize_t r; 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci r = dso__data_read_offset(dso, machine, offset, 2598c2ecf20Sopenharmony_ci (u8 *) &hdr, sizeof(hdr)); 2608c2ecf20Sopenharmony_ci if (r != sizeof(hdr)) 2618c2ecf20Sopenharmony_ci return -EINVAL; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci /* We dont need eh_frame_ptr, just skip it. */ 2648c2ecf20Sopenharmony_ci dw_read_encoded_value(enc, end, hdr.eh_frame_ptr_enc); 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci *fde_count = dw_read_encoded_value(enc, end, hdr.fde_count_enc); 2678c2ecf20Sopenharmony_ci *segbase = offset; 2688c2ecf20Sopenharmony_ci *table_data = (enc - (u8 *) &hdr) + offset; 2698c2ecf20Sopenharmony_ci return 0; 2708c2ecf20Sopenharmony_ci} 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_cistatic int read_unwind_spec_eh_frame(struct dso *dso, struct machine *machine, 2738c2ecf20Sopenharmony_ci u64 *table_data, u64 *segbase, 2748c2ecf20Sopenharmony_ci u64 *fde_count) 2758c2ecf20Sopenharmony_ci{ 2768c2ecf20Sopenharmony_ci int ret = -EINVAL, fd; 2778c2ecf20Sopenharmony_ci u64 offset = dso->data.eh_frame_hdr_offset; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci if (offset == 0) { 2808c2ecf20Sopenharmony_ci fd = dso__data_get_fd(dso, machine); 2818c2ecf20Sopenharmony_ci if (fd < 0) 2828c2ecf20Sopenharmony_ci return -EINVAL; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci /* Check the .eh_frame section for unwinding info */ 2858c2ecf20Sopenharmony_ci offset = elf_section_offset(fd, ".eh_frame_hdr"); 2868c2ecf20Sopenharmony_ci dso->data.eh_frame_hdr_offset = offset; 2878c2ecf20Sopenharmony_ci dso__data_put_fd(dso); 2888c2ecf20Sopenharmony_ci } 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci if (offset) 2918c2ecf20Sopenharmony_ci ret = unwind_spec_ehframe(dso, machine, offset, 2928c2ecf20Sopenharmony_ci table_data, segbase, 2938c2ecf20Sopenharmony_ci fde_count); 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci return ret; 2968c2ecf20Sopenharmony_ci} 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci#ifndef NO_LIBUNWIND_DEBUG_FRAME 2998c2ecf20Sopenharmony_cistatic int read_unwind_spec_debug_frame(struct dso *dso, 3008c2ecf20Sopenharmony_ci struct machine *machine, u64 *offset) 3018c2ecf20Sopenharmony_ci{ 3028c2ecf20Sopenharmony_ci int fd; 3038c2ecf20Sopenharmony_ci u64 ofs = dso->data.debug_frame_offset; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci /* debug_frame can reside in: 3068c2ecf20Sopenharmony_ci * - dso 3078c2ecf20Sopenharmony_ci * - debug pointed by symsrc_filename 3088c2ecf20Sopenharmony_ci * - gnu_debuglink, which doesn't necessary 3098c2ecf20Sopenharmony_ci * has to be pointed by symsrc_filename 3108c2ecf20Sopenharmony_ci */ 3118c2ecf20Sopenharmony_ci if (ofs == 0) { 3128c2ecf20Sopenharmony_ci fd = dso__data_get_fd(dso, machine); 3138c2ecf20Sopenharmony_ci if (fd >= 0) { 3148c2ecf20Sopenharmony_ci ofs = elf_section_offset(fd, ".debug_frame"); 3158c2ecf20Sopenharmony_ci dso__data_put_fd(dso); 3168c2ecf20Sopenharmony_ci } 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci if (ofs <= 0) { 3198c2ecf20Sopenharmony_ci fd = open(dso->symsrc_filename, O_RDONLY); 3208c2ecf20Sopenharmony_ci if (fd >= 0) { 3218c2ecf20Sopenharmony_ci ofs = elf_section_offset(fd, ".debug_frame"); 3228c2ecf20Sopenharmony_ci close(fd); 3238c2ecf20Sopenharmony_ci } 3248c2ecf20Sopenharmony_ci } 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci if (ofs <= 0) { 3278c2ecf20Sopenharmony_ci char *debuglink = malloc(PATH_MAX); 3288c2ecf20Sopenharmony_ci int ret = 0; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci ret = dso__read_binary_type_filename( 3318c2ecf20Sopenharmony_ci dso, DSO_BINARY_TYPE__DEBUGLINK, 3328c2ecf20Sopenharmony_ci machine->root_dir, debuglink, PATH_MAX); 3338c2ecf20Sopenharmony_ci if (!ret) { 3348c2ecf20Sopenharmony_ci fd = open(debuglink, O_RDONLY); 3358c2ecf20Sopenharmony_ci if (fd >= 0) { 3368c2ecf20Sopenharmony_ci ofs = elf_section_offset(fd, 3378c2ecf20Sopenharmony_ci ".debug_frame"); 3388c2ecf20Sopenharmony_ci close(fd); 3398c2ecf20Sopenharmony_ci } 3408c2ecf20Sopenharmony_ci } 3418c2ecf20Sopenharmony_ci if (ofs > 0) { 3428c2ecf20Sopenharmony_ci if (dso->symsrc_filename != NULL) { 3438c2ecf20Sopenharmony_ci pr_warning( 3448c2ecf20Sopenharmony_ci "%s: overwrite symsrc(%s,%s)\n", 3458c2ecf20Sopenharmony_ci __func__, 3468c2ecf20Sopenharmony_ci dso->symsrc_filename, 3478c2ecf20Sopenharmony_ci debuglink); 3488c2ecf20Sopenharmony_ci zfree(&dso->symsrc_filename); 3498c2ecf20Sopenharmony_ci } 3508c2ecf20Sopenharmony_ci dso->symsrc_filename = debuglink; 3518c2ecf20Sopenharmony_ci } else { 3528c2ecf20Sopenharmony_ci free(debuglink); 3538c2ecf20Sopenharmony_ci } 3548c2ecf20Sopenharmony_ci } 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci dso->data.debug_frame_offset = ofs; 3578c2ecf20Sopenharmony_ci } 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci *offset = ofs; 3608c2ecf20Sopenharmony_ci if (*offset) 3618c2ecf20Sopenharmony_ci return 0; 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci return -EINVAL; 3648c2ecf20Sopenharmony_ci} 3658c2ecf20Sopenharmony_ci#endif 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_cistatic struct map *find_map(unw_word_t ip, struct unwind_info *ui) 3688c2ecf20Sopenharmony_ci{ 3698c2ecf20Sopenharmony_ci struct addr_location al; 3708c2ecf20Sopenharmony_ci return thread__find_map(ui->thread, PERF_RECORD_MISC_USER, ip, &al); 3718c2ecf20Sopenharmony_ci} 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_cistatic int 3748c2ecf20Sopenharmony_cifind_proc_info(unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi, 3758c2ecf20Sopenharmony_ci int need_unwind_info, void *arg) 3768c2ecf20Sopenharmony_ci{ 3778c2ecf20Sopenharmony_ci struct unwind_info *ui = arg; 3788c2ecf20Sopenharmony_ci struct map *map; 3798c2ecf20Sopenharmony_ci unw_dyn_info_t di; 3808c2ecf20Sopenharmony_ci u64 table_data, segbase, fde_count; 3818c2ecf20Sopenharmony_ci int ret = -EINVAL; 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci map = find_map(ip, ui); 3848c2ecf20Sopenharmony_ci if (!map || !map->dso) 3858c2ecf20Sopenharmony_ci return -EINVAL; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci pr_debug("unwind: find_proc_info dso %s\n", map->dso->name); 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci /* Check the .eh_frame section for unwinding info */ 3908c2ecf20Sopenharmony_ci if (!read_unwind_spec_eh_frame(map->dso, ui->machine, 3918c2ecf20Sopenharmony_ci &table_data, &segbase, &fde_count)) { 3928c2ecf20Sopenharmony_ci memset(&di, 0, sizeof(di)); 3938c2ecf20Sopenharmony_ci di.format = UNW_INFO_FORMAT_REMOTE_TABLE; 3948c2ecf20Sopenharmony_ci di.start_ip = map->start; 3958c2ecf20Sopenharmony_ci di.end_ip = map->end; 3968c2ecf20Sopenharmony_ci di.u.rti.segbase = map->start + segbase - map->pgoff; 3978c2ecf20Sopenharmony_ci di.u.rti.table_data = map->start + table_data - map->pgoff; 3988c2ecf20Sopenharmony_ci di.u.rti.table_len = fde_count * sizeof(struct table_entry) 3998c2ecf20Sopenharmony_ci / sizeof(unw_word_t); 4008c2ecf20Sopenharmony_ci ret = dwarf_search_unwind_table(as, ip, &di, pi, 4018c2ecf20Sopenharmony_ci need_unwind_info, arg); 4028c2ecf20Sopenharmony_ci } 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci#ifndef NO_LIBUNWIND_DEBUG_FRAME 4058c2ecf20Sopenharmony_ci /* Check the .debug_frame section for unwinding info */ 4068c2ecf20Sopenharmony_ci if (ret < 0 && 4078c2ecf20Sopenharmony_ci !read_unwind_spec_debug_frame(map->dso, ui->machine, &segbase)) { 4088c2ecf20Sopenharmony_ci int fd = dso__data_get_fd(map->dso, ui->machine); 4098c2ecf20Sopenharmony_ci int is_exec = elf_is_exec(fd, map->dso->name); 4108c2ecf20Sopenharmony_ci unw_word_t base = is_exec ? 0 : map->start; 4118c2ecf20Sopenharmony_ci const char *symfile; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci if (fd >= 0) 4148c2ecf20Sopenharmony_ci dso__data_put_fd(map->dso); 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci symfile = map->dso->symsrc_filename ?: map->dso->name; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci memset(&di, 0, sizeof(di)); 4198c2ecf20Sopenharmony_ci if (dwarf_find_debug_frame(0, &di, ip, base, symfile, 4208c2ecf20Sopenharmony_ci map->start, map->end)) 4218c2ecf20Sopenharmony_ci return dwarf_search_unwind_table(as, ip, &di, pi, 4228c2ecf20Sopenharmony_ci need_unwind_info, arg); 4238c2ecf20Sopenharmony_ci } 4248c2ecf20Sopenharmony_ci#endif 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci return ret; 4278c2ecf20Sopenharmony_ci} 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_cistatic int access_fpreg(unw_addr_space_t __maybe_unused as, 4308c2ecf20Sopenharmony_ci unw_regnum_t __maybe_unused num, 4318c2ecf20Sopenharmony_ci unw_fpreg_t __maybe_unused *val, 4328c2ecf20Sopenharmony_ci int __maybe_unused __write, 4338c2ecf20Sopenharmony_ci void __maybe_unused *arg) 4348c2ecf20Sopenharmony_ci{ 4358c2ecf20Sopenharmony_ci pr_err("unwind: access_fpreg unsupported\n"); 4368c2ecf20Sopenharmony_ci return -UNW_EINVAL; 4378c2ecf20Sopenharmony_ci} 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_cistatic int get_dyn_info_list_addr(unw_addr_space_t __maybe_unused as, 4408c2ecf20Sopenharmony_ci unw_word_t __maybe_unused *dil_addr, 4418c2ecf20Sopenharmony_ci void __maybe_unused *arg) 4428c2ecf20Sopenharmony_ci{ 4438c2ecf20Sopenharmony_ci return -UNW_ENOINFO; 4448c2ecf20Sopenharmony_ci} 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_cistatic int resume(unw_addr_space_t __maybe_unused as, 4478c2ecf20Sopenharmony_ci unw_cursor_t __maybe_unused *cu, 4488c2ecf20Sopenharmony_ci void __maybe_unused *arg) 4498c2ecf20Sopenharmony_ci{ 4508c2ecf20Sopenharmony_ci pr_err("unwind: resume unsupported\n"); 4518c2ecf20Sopenharmony_ci return -UNW_EINVAL; 4528c2ecf20Sopenharmony_ci} 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_cistatic int 4558c2ecf20Sopenharmony_ciget_proc_name(unw_addr_space_t __maybe_unused as, 4568c2ecf20Sopenharmony_ci unw_word_t __maybe_unused addr, 4578c2ecf20Sopenharmony_ci char __maybe_unused *bufp, size_t __maybe_unused buf_len, 4588c2ecf20Sopenharmony_ci unw_word_t __maybe_unused *offp, void __maybe_unused *arg) 4598c2ecf20Sopenharmony_ci{ 4608c2ecf20Sopenharmony_ci pr_err("unwind: get_proc_name unsupported\n"); 4618c2ecf20Sopenharmony_ci return -UNW_EINVAL; 4628c2ecf20Sopenharmony_ci} 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_cistatic int access_dso_mem(struct unwind_info *ui, unw_word_t addr, 4658c2ecf20Sopenharmony_ci unw_word_t *data) 4668c2ecf20Sopenharmony_ci{ 4678c2ecf20Sopenharmony_ci struct map *map; 4688c2ecf20Sopenharmony_ci ssize_t size; 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci map = find_map(addr, ui); 4718c2ecf20Sopenharmony_ci if (!map) { 4728c2ecf20Sopenharmony_ci pr_debug("unwind: no map for %lx\n", (unsigned long)addr); 4738c2ecf20Sopenharmony_ci return -1; 4748c2ecf20Sopenharmony_ci } 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci if (!map->dso) 4778c2ecf20Sopenharmony_ci return -1; 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci size = dso__data_read_addr(map->dso, map, ui->machine, 4808c2ecf20Sopenharmony_ci addr, (u8 *) data, sizeof(*data)); 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci return !(size == sizeof(*data)); 4838c2ecf20Sopenharmony_ci} 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_cistatic int access_mem(unw_addr_space_t __maybe_unused as, 4868c2ecf20Sopenharmony_ci unw_word_t addr, unw_word_t *valp, 4878c2ecf20Sopenharmony_ci int __write, void *arg) 4888c2ecf20Sopenharmony_ci{ 4898c2ecf20Sopenharmony_ci struct unwind_info *ui = arg; 4908c2ecf20Sopenharmony_ci struct stack_dump *stack = &ui->sample->user_stack; 4918c2ecf20Sopenharmony_ci u64 start, end; 4928c2ecf20Sopenharmony_ci int offset; 4938c2ecf20Sopenharmony_ci int ret; 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci /* Don't support write, probably not needed. */ 4968c2ecf20Sopenharmony_ci if (__write || !stack || !ui->sample->user_regs.regs) { 4978c2ecf20Sopenharmony_ci *valp = 0; 4988c2ecf20Sopenharmony_ci return 0; 4998c2ecf20Sopenharmony_ci } 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci ret = perf_reg_value(&start, &ui->sample->user_regs, 5028c2ecf20Sopenharmony_ci LIBUNWIND__ARCH_REG_SP); 5038c2ecf20Sopenharmony_ci if (ret) 5048c2ecf20Sopenharmony_ci return ret; 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci end = start + stack->size; 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci /* Check overflow. */ 5098c2ecf20Sopenharmony_ci if (addr + sizeof(unw_word_t) < addr) 5108c2ecf20Sopenharmony_ci return -EINVAL; 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci if (addr < start || addr + sizeof(unw_word_t) >= end) { 5138c2ecf20Sopenharmony_ci ret = access_dso_mem(ui, addr, valp); 5148c2ecf20Sopenharmony_ci if (ret) { 5158c2ecf20Sopenharmony_ci pr_debug("unwind: access_mem %p not inside range" 5168c2ecf20Sopenharmony_ci " 0x%" PRIx64 "-0x%" PRIx64 "\n", 5178c2ecf20Sopenharmony_ci (void *) (uintptr_t) addr, start, end); 5188c2ecf20Sopenharmony_ci *valp = 0; 5198c2ecf20Sopenharmony_ci return ret; 5208c2ecf20Sopenharmony_ci } 5218c2ecf20Sopenharmony_ci return 0; 5228c2ecf20Sopenharmony_ci } 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci offset = addr - start; 5258c2ecf20Sopenharmony_ci *valp = *(unw_word_t *)&stack->data[offset]; 5268c2ecf20Sopenharmony_ci pr_debug("unwind: access_mem addr %p val %lx, offset %d\n", 5278c2ecf20Sopenharmony_ci (void *) (uintptr_t) addr, (unsigned long)*valp, offset); 5288c2ecf20Sopenharmony_ci return 0; 5298c2ecf20Sopenharmony_ci} 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_cistatic int access_reg(unw_addr_space_t __maybe_unused as, 5328c2ecf20Sopenharmony_ci unw_regnum_t regnum, unw_word_t *valp, 5338c2ecf20Sopenharmony_ci int __write, void *arg) 5348c2ecf20Sopenharmony_ci{ 5358c2ecf20Sopenharmony_ci struct unwind_info *ui = arg; 5368c2ecf20Sopenharmony_ci int id, ret; 5378c2ecf20Sopenharmony_ci u64 val; 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci /* Don't support write, I suspect we don't need it. */ 5408c2ecf20Sopenharmony_ci if (__write) { 5418c2ecf20Sopenharmony_ci pr_err("unwind: access_reg w %d\n", regnum); 5428c2ecf20Sopenharmony_ci return 0; 5438c2ecf20Sopenharmony_ci } 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci if (!ui->sample->user_regs.regs) { 5468c2ecf20Sopenharmony_ci *valp = 0; 5478c2ecf20Sopenharmony_ci return 0; 5488c2ecf20Sopenharmony_ci } 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci id = LIBUNWIND__ARCH_REG_ID(regnum); 5518c2ecf20Sopenharmony_ci if (id < 0) 5528c2ecf20Sopenharmony_ci return -EINVAL; 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci ret = perf_reg_value(&val, &ui->sample->user_regs, id); 5558c2ecf20Sopenharmony_ci if (ret) { 5568c2ecf20Sopenharmony_ci pr_err("unwind: can't read reg %d\n", regnum); 5578c2ecf20Sopenharmony_ci return ret; 5588c2ecf20Sopenharmony_ci } 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci *valp = (unw_word_t) val; 5618c2ecf20Sopenharmony_ci pr_debug("unwind: reg %d, val %lx\n", regnum, (unsigned long)*valp); 5628c2ecf20Sopenharmony_ci return 0; 5638c2ecf20Sopenharmony_ci} 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_cistatic void put_unwind_info(unw_addr_space_t __maybe_unused as, 5668c2ecf20Sopenharmony_ci unw_proc_info_t *pi __maybe_unused, 5678c2ecf20Sopenharmony_ci void *arg __maybe_unused) 5688c2ecf20Sopenharmony_ci{ 5698c2ecf20Sopenharmony_ci pr_debug("unwind: put_unwind_info called\n"); 5708c2ecf20Sopenharmony_ci} 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_cistatic int entry(u64 ip, struct thread *thread, 5738c2ecf20Sopenharmony_ci unwind_entry_cb_t cb, void *arg) 5748c2ecf20Sopenharmony_ci{ 5758c2ecf20Sopenharmony_ci struct unwind_entry e; 5768c2ecf20Sopenharmony_ci struct addr_location al; 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci e.ms.sym = thread__find_symbol(thread, PERF_RECORD_MISC_USER, ip, &al); 5798c2ecf20Sopenharmony_ci e.ip = ip; 5808c2ecf20Sopenharmony_ci e.ms.map = al.map; 5818c2ecf20Sopenharmony_ci e.ms.maps = al.maps; 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci pr_debug("unwind: %s:ip = 0x%" PRIx64 " (0x%" PRIx64 ")\n", 5848c2ecf20Sopenharmony_ci al.sym ? al.sym->name : "''", 5858c2ecf20Sopenharmony_ci ip, 5868c2ecf20Sopenharmony_ci al.map ? al.map->map_ip(al.map, ip) : (u64) 0); 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci return cb(&e, arg); 5898c2ecf20Sopenharmony_ci} 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_cistatic void display_error(int err) 5928c2ecf20Sopenharmony_ci{ 5938c2ecf20Sopenharmony_ci switch (err) { 5948c2ecf20Sopenharmony_ci case UNW_EINVAL: 5958c2ecf20Sopenharmony_ci pr_err("unwind: Only supports local.\n"); 5968c2ecf20Sopenharmony_ci break; 5978c2ecf20Sopenharmony_ci case UNW_EUNSPEC: 5988c2ecf20Sopenharmony_ci pr_err("unwind: Unspecified error.\n"); 5998c2ecf20Sopenharmony_ci break; 6008c2ecf20Sopenharmony_ci case UNW_EBADREG: 6018c2ecf20Sopenharmony_ci pr_err("unwind: Register unavailable.\n"); 6028c2ecf20Sopenharmony_ci break; 6038c2ecf20Sopenharmony_ci default: 6048c2ecf20Sopenharmony_ci break; 6058c2ecf20Sopenharmony_ci } 6068c2ecf20Sopenharmony_ci} 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_cistatic unw_accessors_t accessors = { 6098c2ecf20Sopenharmony_ci .find_proc_info = find_proc_info, 6108c2ecf20Sopenharmony_ci .put_unwind_info = put_unwind_info, 6118c2ecf20Sopenharmony_ci .get_dyn_info_list_addr = get_dyn_info_list_addr, 6128c2ecf20Sopenharmony_ci .access_mem = access_mem, 6138c2ecf20Sopenharmony_ci .access_reg = access_reg, 6148c2ecf20Sopenharmony_ci .access_fpreg = access_fpreg, 6158c2ecf20Sopenharmony_ci .resume = resume, 6168c2ecf20Sopenharmony_ci .get_proc_name = get_proc_name, 6178c2ecf20Sopenharmony_ci}; 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_cistatic int _unwind__prepare_access(struct maps *maps) 6208c2ecf20Sopenharmony_ci{ 6218c2ecf20Sopenharmony_ci maps->addr_space = unw_create_addr_space(&accessors, 0); 6228c2ecf20Sopenharmony_ci if (!maps->addr_space) { 6238c2ecf20Sopenharmony_ci pr_err("unwind: Can't create unwind address space.\n"); 6248c2ecf20Sopenharmony_ci return -ENOMEM; 6258c2ecf20Sopenharmony_ci } 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci unw_set_caching_policy(maps->addr_space, UNW_CACHE_GLOBAL); 6288c2ecf20Sopenharmony_ci return 0; 6298c2ecf20Sopenharmony_ci} 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_cistatic void _unwind__flush_access(struct maps *maps) 6328c2ecf20Sopenharmony_ci{ 6338c2ecf20Sopenharmony_ci unw_flush_cache(maps->addr_space, 0, 0); 6348c2ecf20Sopenharmony_ci} 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_cistatic void _unwind__finish_access(struct maps *maps) 6378c2ecf20Sopenharmony_ci{ 6388c2ecf20Sopenharmony_ci unw_destroy_addr_space(maps->addr_space); 6398c2ecf20Sopenharmony_ci} 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_cistatic int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb, 6428c2ecf20Sopenharmony_ci void *arg, int max_stack) 6438c2ecf20Sopenharmony_ci{ 6448c2ecf20Sopenharmony_ci u64 val; 6458c2ecf20Sopenharmony_ci unw_word_t ips[max_stack]; 6468c2ecf20Sopenharmony_ci unw_addr_space_t addr_space; 6478c2ecf20Sopenharmony_ci unw_cursor_t c; 6488c2ecf20Sopenharmony_ci int ret, i = 0; 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci ret = perf_reg_value(&val, &ui->sample->user_regs, 6518c2ecf20Sopenharmony_ci LIBUNWIND__ARCH_REG_IP); 6528c2ecf20Sopenharmony_ci if (ret) 6538c2ecf20Sopenharmony_ci return ret; 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci ips[i++] = (unw_word_t) val; 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci /* 6588c2ecf20Sopenharmony_ci * If we need more than one entry, do the DWARF 6598c2ecf20Sopenharmony_ci * unwind itself. 6608c2ecf20Sopenharmony_ci */ 6618c2ecf20Sopenharmony_ci if (max_stack - 1 > 0) { 6628c2ecf20Sopenharmony_ci WARN_ONCE(!ui->thread, "WARNING: ui->thread is NULL"); 6638c2ecf20Sopenharmony_ci addr_space = ui->thread->maps->addr_space; 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci if (addr_space == NULL) 6668c2ecf20Sopenharmony_ci return -1; 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci ret = unw_init_remote(&c, addr_space, ui); 6698c2ecf20Sopenharmony_ci if (ret) 6708c2ecf20Sopenharmony_ci display_error(ret); 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci while (!ret && (unw_step(&c) > 0) && i < max_stack) { 6738c2ecf20Sopenharmony_ci unw_get_reg(&c, UNW_REG_IP, &ips[i]); 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci /* 6768c2ecf20Sopenharmony_ci * Decrement the IP for any non-activation frames. 6778c2ecf20Sopenharmony_ci * this is required to properly find the srcline 6788c2ecf20Sopenharmony_ci * for caller frames. 6798c2ecf20Sopenharmony_ci * See also the documentation for dwfl_frame_pc(), 6808c2ecf20Sopenharmony_ci * which this code tries to replicate. 6818c2ecf20Sopenharmony_ci */ 6828c2ecf20Sopenharmony_ci if (unw_is_signal_frame(&c) <= 0) 6838c2ecf20Sopenharmony_ci --ips[i]; 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci ++i; 6868c2ecf20Sopenharmony_ci } 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci max_stack = i; 6898c2ecf20Sopenharmony_ci } 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci /* 6928c2ecf20Sopenharmony_ci * Display what we got based on the order setup. 6938c2ecf20Sopenharmony_ci */ 6948c2ecf20Sopenharmony_ci for (i = 0; i < max_stack && !ret; i++) { 6958c2ecf20Sopenharmony_ci int j = i; 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci if (callchain_param.order == ORDER_CALLER) 6988c2ecf20Sopenharmony_ci j = max_stack - i - 1; 6998c2ecf20Sopenharmony_ci ret = ips[j] ? entry(ips[j], ui->thread, cb, arg) : 0; 7008c2ecf20Sopenharmony_ci } 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci return ret; 7038c2ecf20Sopenharmony_ci} 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_cistatic int _unwind__get_entries(unwind_entry_cb_t cb, void *arg, 7068c2ecf20Sopenharmony_ci struct thread *thread, 7078c2ecf20Sopenharmony_ci struct perf_sample *data, int max_stack) 7088c2ecf20Sopenharmony_ci{ 7098c2ecf20Sopenharmony_ci struct unwind_info ui = { 7108c2ecf20Sopenharmony_ci .sample = data, 7118c2ecf20Sopenharmony_ci .thread = thread, 7128c2ecf20Sopenharmony_ci .machine = thread->maps->machine, 7138c2ecf20Sopenharmony_ci }; 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci if (!data->user_regs.regs) 7168c2ecf20Sopenharmony_ci return -EINVAL; 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci if (max_stack <= 0) 7198c2ecf20Sopenharmony_ci return -EINVAL; 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci return get_entries(&ui, cb, arg, max_stack); 7228c2ecf20Sopenharmony_ci} 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_cistatic struct unwind_libunwind_ops 7258c2ecf20Sopenharmony_ci_unwind_libunwind_ops = { 7268c2ecf20Sopenharmony_ci .prepare_access = _unwind__prepare_access, 7278c2ecf20Sopenharmony_ci .flush_access = _unwind__flush_access, 7288c2ecf20Sopenharmony_ci .finish_access = _unwind__finish_access, 7298c2ecf20Sopenharmony_ci .get_entries = _unwind__get_entries, 7308c2ecf20Sopenharmony_ci}; 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci#ifndef REMOTE_UNWIND_LIBUNWIND 7338c2ecf20Sopenharmony_cistruct unwind_libunwind_ops * 7348c2ecf20Sopenharmony_cilocal_unwind_libunwind_ops = &_unwind_libunwind_ops; 7358c2ecf20Sopenharmony_ci#endif 736