summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
authorzy <[email protected]>2023-11-24 01:22:30 -0500
committerzy <[email protected]>2023-11-24 01:22:30 -0500
commit59993f7e3740f0aaa06483b9eb50d1d25349c0fa (patch)
tree27fbb4351504177352380b54908c507f50cf2ecd /source
parent85fd3e79aec31356876d7a2b25654c5a681fdc1c (diff)
libunwind make success
Diffstat (limited to 'source')
-rw-r--r--source/ucli_py/libunwind/Makefile18
-rw-r--r--source/ucli_py/libunwind/accessors.cc483
-rw-r--r--source/ucli_py/libunwind/symbol.cc32
-rw-r--r--source/ucli_py/libunwind/symbol.h (renamed from source/ucli_py/unwind/symbol.h)58
-rw-r--r--source/ucli_py/libunwind/unwind.cc131
-rw-r--r--source/ucli_py/libunwind/unwind.h103
-rw-r--r--source/ucli_py/unwind/Makefile29
-rw-r--r--source/ucli_py/unwind/elf.cc566
-rw-r--r--source/ucli_py/unwind/elf.h25
-rw-r--r--source/ucli_py/unwind/internal.h189
-rw-r--r--source/ucli_py/unwind/symbol.cc504
-rw-r--r--source/ucli_py/unwind/unwind.cc684
-rw-r--r--source/ucli_py/unwind/unwind.h101
13 files changed, 786 insertions, 2137 deletions
diff --git a/source/ucli_py/libunwind/Makefile b/source/ucli_py/libunwind/Makefile
new file mode 100644
index 0000000..2c7ba94
--- /dev/null
+++ b/source/ucli_py/libunwind/Makefile
@@ -0,0 +1,18 @@
+TARGET_SO=libunwind.so
+SOURCES=unwind.cc symbol.cc
+OBJECTS=$(SOURCES:.cc=.o)
+
+INCLUDES=-I.
+
+CFLAGS=-g -O0 -fPIC
+
+LFLAGS=-shared
+
+%.o: %.cc
+ $(CXX) $(CFLAGS) $(INCLUDES) -c $< -o $@
+
+$(TARGET_SO): $(OBJECTS)
+ $(CXX) $(LFLAGS) $^ -o $@
+
+clean:
+ rm -f $(TARGET_SO) $(OBJECTS) \ No newline at end of file
diff --git a/source/ucli_py/libunwind/accessors.cc b/source/ucli_py/libunwind/accessors.cc
new file mode 100644
index 0000000..5c39a98
--- /dev/null
+++ b/source/ucli_py/libunwind/accessors.cc
@@ -0,0 +1,483 @@
+#include <fcntl.h>
+#include <gelf.h> // for GElf_Ehdr | Elf
+#include <string.h>
+#include <unistd.h>
+
+#include "unwind.h"
+
+extern "C" {
+int UNW_OBJ(dwarf_search_unwind_table)(unw_addr_space_t as, unw_word_t ip,
+ unw_dyn_info_t *di, unw_proc_info_t *pi,
+ int need_unwind_info, void *arg);
+}
+
+#define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table)
+
+#define DW_EH_PE_FORMAT_MASK 0x0f /* format of the encoded value */
+#define DW_EH_PE_APPL_MASK 0x70 /* how the value is to be applied */
+
+/* Pointer-encoding formats: */
+#define DW_EH_PE_omit 0xff
+#define DW_EH_PE_ptr 0x00 /* pointer-sized unsigned value */
+#define DW_EH_PE_udata4 0x03 /* unsigned 32-bit value */
+#define DW_EH_PE_udata8 0x04 /* unsigned 64-bit value */
+#define DW_EH_PE_sdata4 0x0b /* signed 32-bit value */
+#define DW_EH_PE_sdata8 0x0c /* signed 64-bit value */
+
+/* Pointer-encoding application: */
+#define DW_EH_PE_absptr 0x00 /* absolute value */
+#define DW_EH_PE_pcrel 0x10 /* rel. to addr. of encoded value */
+
+unw_accessors_t accessors = {
+ .find_proc_info = find_proc_info,
+ .put_unwind_info = put_unwind_info,
+ .get_dyn_info_list_addr = get_dyn_info_list_addr,
+ .access_mem = access_mem,
+ .access_reg = access_reg,
+ .access_fpreg = access_fpreg,
+ .resume = resume,
+ .get_proc_name = get_proc_name,
+};
+
+static vma *find_map(unw_word_t ip, struct unwind_info *ui) {
+ return ui->sp->find_vma(ui->pid, ip);
+}
+
+static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, GElf_Shdr *shp,
+ const char *name) {
+ Elf_Scn *sec = NULL;
+
+ while ((sec = elf_nextscn(elf, sec)) != NULL) {
+ char *str;
+
+ gelf_getshdr(sec, shp);
+ str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name);
+ if (!strcmp(name, str)) break;
+ }
+
+ return sec;
+}
+
+static u64 elf_section_offset(int fd, const char *name) {
+ Elf *elf;
+ GElf_Ehdr ehdr;
+ GElf_Shdr shdr;
+ u64 offset = 0;
+
+ elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
+ if (elf == NULL) return 0;
+
+ do {
+ if (gelf_getehdr(elf, &ehdr) == NULL) break;
+
+ if (!elf_section_by_name(elf, &ehdr, &shdr, name)) break;
+
+ offset = shdr.sh_offset;
+ } while (0);
+
+ elf_end(elf);
+ return offset;
+}
+
+struct eh_frame_hdr {
+ unsigned char version;
+ unsigned char eh_frame_ptr_enc;
+ unsigned char fde_count_enc;
+ unsigned char table_enc;
+
+ /*
+ * The rest of the header is variable-length and consists of the
+ * following members:
+ *
+ * encoded_t eh_frame_ptr;
+ * encoded_t fde_count;
+ */
+
+ /* A single encoded pointer should not be more than 8 bytes. */
+ u64 enc[2];
+
+ /*
+ * struct {
+ * encoded_t start_ip;
+ * encoded_t fde_addr;
+ * } binary_search_table[fde_count];
+ */
+ char data[0];
+} __attribute__((__packed__));
+
+ssize_t dso_read(vma *dso, u64 offset, u8 *data, ssize_t size) {
+ ssize_t ret = -1;
+ int fd;
+
+ fd = dso_data_fd(dso);
+ if (fd < 0) return -1;
+
+ do {
+ if (-1 == lseek(fd, offset, SEEK_SET)) break;
+
+ ret = read(fd, data, size);
+ if (ret <= 0) break;
+ } while (0);
+
+ close(fd);
+ return ret;
+}
+
+ssize_t dso__data_read_offset(vma *dso, u64 offset, u8 *data, ssize_t size) {
+ ssize_t r = 0;
+ u8 *p = data;
+
+ do {
+ ssize_t ret;
+ ret = dso_read(dso, offset, p, size);
+ if (ret <= 0) {
+ return -1;
+ }
+ if (ret > size) {
+ return -1;
+ }
+ r += ret;
+ p += ret;
+ offset += ret;
+ size -= ret;
+ } while (size);
+ return r;
+}
+
+#define dw_read(ptr, type, end) \
+ ({ \
+ type *__p = (type *)ptr; \
+ type __v; \
+ if ((__p + 1) > (type *)end) return -EINVAL; \
+ __v = *__p++; \
+ ptr = (typeof(ptr))__p; \
+ __v; \
+ })
+
+static int __dw_read_encoded_value(u8 **p, u8 *end, u64 *val, u8 encoding) {
+ u8 *cur = *p;
+ *val = 0;
+
+ switch (encoding) {
+ case DW_EH_PE_omit:
+ *val = 0;
+ goto out;
+ case DW_EH_PE_ptr:
+ *val = dw_read(cur, unsigned long, end);
+ goto out;
+ default:
+ break;
+ }
+
+ switch (encoding & DW_EH_PE_APPL_MASK) {
+ case DW_EH_PE_absptr:
+ break;
+ case DW_EH_PE_pcrel:
+ *val = (unsigned long)cur;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if ((encoding & 0x07) == 0x00) encoding |= DW_EH_PE_udata4;
+
+ switch (encoding & DW_EH_PE_FORMAT_MASK) {
+ case DW_EH_PE_sdata4:
+ *val += dw_read(cur, s32, end);
+ break;
+ case DW_EH_PE_udata4:
+ *val += dw_read(cur, u32, end);
+ break;
+ case DW_EH_PE_sdata8:
+ *val += dw_read(cur, s64, end);
+ break;
+ case DW_EH_PE_udata8:
+ *val += dw_read(cur, u64, end);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+out:
+ *p = cur;
+ return 0;
+}
+
+#define dw_read_encoded_value(ptr, end, enc) \
+ ({ \
+ u64 __v; \
+ if (__dw_read_encoded_value(&ptr, end, &__v, enc)) { \
+ return -EINVAL; \
+ } \
+ __v; \
+ })
+
+static int unwind_spec_ehframe(vma *dso, u64 offset, u64 *table_data,
+ u64 *segbase, u64 *fde_count) {
+ struct eh_frame_hdr hdr;
+ u8 *enc = (u8 *)&hdr.enc;
+ u8 *end = (u8 *)&hdr.data;
+ ssize_t r;
+
+ r = dso__data_read_offset(dso, offset, (u8 *)&hdr, sizeof(hdr));
+ if (r != sizeof(hdr)) {
+ return -EINVAL;
+ }
+
+ /* We dont need eh_frame_ptr, just skip it. */
+ dw_read_encoded_value(enc, end, hdr.eh_frame_ptr_enc);
+
+ *fde_count = dw_read_encoded_value(enc, end, hdr.fde_count_enc);
+ *segbase = offset;
+ *table_data = (enc - (u8 *)&hdr) + offset;
+
+ return 0;
+}
+
+int dso_data_fd(vma *dso) { return open(dso->name.c_str(), O_RDONLY); }
+
+static int read_unwind_spec(vma *dso, u64 *table_data, u64 *segbase,
+ u64 *fde_count) {
+ int ret = -EINVAL, fd;
+
+ if (dso->eh_frame_hdr_offset == 0 && dso->elf_read_error == 0) {
+ fd = dso_data_fd(dso);
+ if (fd < 0) return -EINVAL;
+
+ dso->eh_frame_hdr_offset = elf_section_offset(fd, ".eh_frame_hdr");
+ close(fd);
+ ret = unwind_spec_ehframe(dso, dso->eh_frame_hdr_offset, &dso->table_data,
+ &dso->eh_frame_hdr_offset, &dso->fde_count);
+ if (ret != 0) {
+ dso->eh_frame_hdr_offset = 0;
+ dso->elf_read_error = 1;
+ return -EINVAL;
+ }
+ }
+
+ *table_data = dso->table_data;
+ *segbase = dso->eh_frame_hdr_offset;
+ *fde_count = dso->fde_count;
+
+ /* TODO .debug_frame check if eh_frame_hdr fails */
+ return 0;
+}
+
+struct table_entry {
+ u32 start_ip_offset;
+ u32 fde_offset;
+};
+
+static int find_proc_info(unw_addr_space_t as, unw_word_t ip,
+ unw_proc_info_t *pi, int need_unwind_info,
+ void *arg) {
+ struct unwind_info *ui = (struct unwind_info *)arg;
+ unw_dyn_info_t di;
+ u64 table_data, segbase, fde_count;
+
+ vma *map;
+ map = find_map(ip, ui);
+ if (!map) {
+ return -EINVAL;
+ }
+
+ if (!read_unwind_spec(map, &table_data, &segbase, &fde_count)) {
+ memset(&di, 0, sizeof(di));
+ di.format = UNW_INFO_FORMAT_REMOTE_TABLE;
+ di.start_ip = map->start;
+ di.end_ip = map->end;
+ di.u.rti.segbase = map->start + segbase;
+ di.u.rti.table_data = map->start + table_data;
+ di.u.rti.table_len =
+ fde_count * sizeof(struct table_entry) / sizeof(unw_word_t);
+ return dwarf_search_unwind_table(as, ip, &di, pi, need_unwind_info, arg);
+ }
+ // return -EINVAL;
+ return -UNW_ENOINFO;
+}
+
+static void put_unwind_info(unw_addr_space_t as, unw_proc_info_t *pi,
+ void *arg) {
+ // pr_debug("unwind: put_unwind_info called\n");
+}
+
+static int get_dyn_info_list_addr(unw_addr_space_t as, unw_word_t *dil_addr,
+ void *arg) {
+ return -UNW_ENOINFO;
+}
+
+ssize_t dso__data_read_addr(vma *map, u64 addr, u8 *data, ssize_t size) {
+ u64 offset;
+
+ if (map->name.size() > 0 && map->name[0] != '/') return 0;
+
+ offset = addr - map->start + map->offset;
+ return dso__data_read_offset(map, offset, data, size);
+}
+
+struct map *last_map = NULL;
+static int access_dso_mem(struct unwind_info *ui, unw_word_t addr,
+ unw_word_t *data) {
+ ssize_t size;
+
+ // ip in the first page is invalid
+ if (addr == 0 || addr == (unsigned long)(-1) || (long)addr < 4096) {
+ return -UNW_ENOINFO;
+ }
+
+ vma *map;
+ map = find_map(addr, ui);
+ if (!map) {
+ return -UNW_ENOINFO;
+ }
+
+ if (map->type != NATIVE_TYPE) {
+ return -UNW_ENOINFO;
+ }
+
+ size = dso__data_read_addr(map, addr, (u8 *)data, sizeof(*data));
+
+ return !(size == sizeof(*data));
+}
+
+/*
+ * Optimization point.
+ */
+static int reg_value(unw_word_t *valp, struct regs_dump *regs, int id) {
+ /* we only support 3 registers. RIP, RSP and RBP */
+ if (id < 0 || id > 2) return -EINVAL;
+
+ *valp = regs->regs[id];
+ return 0;
+}
+
+unw_word_t last_addr = 0;
+unw_word_t last_val = 0;
+int stack_offset = 0;
+
+static int access_mem(unw_addr_space_t as, unw_word_t addr, unw_word_t *valp,
+ int __write, void *arg) {
+ struct unwind_info *ui = (struct unwind_info *)arg;
+ struct stack_dump *stack = &ui->sample->user_stack;
+ unw_word_t start, end;
+ int offset;
+ int ret;
+
+ if (addr == last_addr) {
+ (*valp) = last_val;
+ return 0;
+ }
+
+ last_addr = addr;
+
+ /* Don't support write, probably not needed. */
+ if (__write || !stack || !ui->sample->user_regs.regs) {
+ *valp = 0;
+ // fprintf(stderr, "access_mem: __write memory\n");
+ last_val = *valp;
+ return 0;
+ }
+
+ /* start is the SP */
+ ret = reg_value(&start, &ui->sample->user_regs, PERF_REG_SP);
+ if (ret) {
+ // fprintf(stderr, "access_mem: reg_value error (ret: %d)\n", ret);
+ return ret;
+ }
+
+ end = start + stack->size;
+
+ /* Check overflow. */
+ if (addr + sizeof(unw_word_t) < addr) {
+ // fprintf(stderr, "access_mem: Check overflow.\n");
+ return -EINVAL;
+ }
+
+ if (addr < start || addr + sizeof(unw_word_t) >= end) {
+ ret = access_dso_mem(ui, addr, valp);
+ if (ret) {
+ // pr_debug("unwind: access_mem %p not inside range %p-%p\n",
+ // (void *)addr, (void *)start, (void *)end);
+ *valp = 0;
+ last_val = 0;
+ return ret;
+ }
+ last_val = *valp;
+ return 0;
+ }
+
+ offset = addr - start;
+ *valp = *(unw_word_t *)&stack->data[offset];
+ last_val = *valp;
+ stack_offset = offset;
+
+ // pr_debug("unwind: access_mem addr %p, val %lx, offset %d\n",
+ // (void *)addr, (unsigned long)*valp, offset);
+ return 0;
+}
+
+int unwind__arch_reg_id(int regnum) {
+ int id;
+
+ switch (regnum) {
+ case UNW_X86_64_RBP:
+ id = PERF_REG_BP;
+ break;
+ case UNW_X86_64_RSP:
+ id = PERF_REG_SP;
+ break;
+ case UNW_X86_64_RIP:
+ id = PERF_REG_IP;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return id;
+}
+
+static int access_reg(unw_addr_space_t as, unw_regnum_t regnum,
+ unw_word_t *valp, int __write, void *arg) {
+ struct unwind_info *ui = (struct unwind_info *)arg;
+ int id, ret;
+
+ /* Don't support write, I suspect we don't need it. */
+ if (__write) {
+ // pr_err("unwind: access_reg w %d\n", regnum);
+ return 0;
+ }
+
+ if (!ui->sample->user_regs.regs) {
+ *valp = 0;
+ return 0;
+ }
+
+ id = unwind__arch_reg_id(regnum);
+ if (id < 0) {
+ // fprintf(stderr, "Cannot get reg: %d\n", regnum);
+ return -EINVAL;
+ }
+
+ ret = reg_value(valp, &ui->sample->user_regs, id);
+ if (ret) {
+ // pr_err("unwind: can't read reg %d\n", regnum);
+ return ret;
+ }
+
+ // pr_debug("unwind: reg %d, val %lx\n", regnum, (unsigned long)*valp);
+ return 0;
+}
+
+static int access_fpreg(unw_addr_space_t as, unw_regnum_t num, unw_fpreg_t *val,
+ int __write, void *arg) {
+ return -UNW_EINVAL;
+}
+
+static int resume(unw_addr_space_t as, unw_cursor_t *cu, void *arg) {
+ return -UNW_EINVAL;
+}
+
+static int get_proc_name(unw_addr_space_t as, unw_word_t addr, char *bufp,
+ size_t buf_len, unw_word_t *offp, void *arg) {
+ return -UNW_EINVAL;
+} \ No newline at end of file
diff --git a/source/ucli_py/libunwind/symbol.cc b/source/ucli_py/libunwind/symbol.cc
new file mode 100644
index 0000000..e3e03a5
--- /dev/null
+++ b/source/ucli_py/libunwind/symbol.cc
@@ -0,0 +1,32 @@
+#include "symbol.h"
+
+symbol_parser g_symbol_parser;
+
+bool symbol_parser::find_vma(pid_t pid, vma &vm)
+{
+ std::map<int, proc_vma>::iterator proc_vma_map;
+
+ proc_vma_map = machine_vma.find(pid);
+ if (proc_vma_map == machine_vma.end()) {
+ return false;
+ }
+
+ proc_vma::const_iterator vma_iter = proc_vma_map->second.upper_bound(vm.pc);
+ if (vma_iter == proc_vma_map->second.end()) {
+ return false;
+ }
+ if (vma_iter->second.end < vm.pc) {
+ return false;
+ }
+
+ if (vma_iter != proc_vma_map->second.begin()) {
+ --vma_iter;
+ }
+
+ vm.start = vma_iter->second.start;
+ vm.end = vma_iter->second.end;
+ vm.name = vma_iter->second.name;
+ vm.offset = vma_iter->second.offset;
+
+ return true;
+} \ No newline at end of file
diff --git a/source/ucli_py/unwind/symbol.h b/source/ucli_py/libunwind/symbol.h
index 52a3855..b32180c 100644
--- a/source/ucli_py/unwind/symbol.h
+++ b/source/ucli_py/libunwind/symbol.h
@@ -1,21 +1,7 @@
-/*
- * Linux内核诊断工具--用户态符号表解析
- *
- * Copyright (C) 2020 Alibaba Ltd.
- *
- * License terms: GNU General Public License (GPL) version 3
- *
- */
-
-#ifndef __PERF_SYMBOL_H__
-#define __PERF_SYMBOL_H__
-
#include <map>
#include <set>
#include <string>
-//#include <boost/icl/interval_map.hpp>
-
#define INVALID_ADDR ((size_t)(-1))
enum {
NATIVE_TYPE = 0,
@@ -55,25 +41,6 @@ struct elf_file {
}
};
-struct symbol {
- size_t start;
- size_t end;
- size_t ip;
- std::string name;
-
- symbol() :start(0), end(0), ip(0) {}
- symbol(size_t pc) :start(0), end(0), ip(pc) {}
-
- void reset(size_t va) { start = end = 0; ip = va; }
- bool operator< (const symbol &sym) const {
- return sym.ip < start;
- }
-
- bool operator> (const symbol &sym) const {
- return sym.ip > end;
- }
-};
-
struct vma {
size_t start;
size_t end;
@@ -117,9 +84,24 @@ struct vma {
}
};
-static inline bool operator==(const vma &lhs, const vma &rhs) {
- return lhs.start == rhs.start && lhs.end == rhs.end && lhs.name == rhs.name;
-}
+struct symbol {
+ size_t start;
+ size_t end;
+ size_t ip;
+ std::string name;
+
+ symbol() :start(0), end(0), ip(0) {}
+ symbol(size_t pc) :start(0), end(0), ip(pc) {}
+
+ void reset(size_t va) { start = end = 0; ip = va; }
+ bool operator< (const symbol &sym) const {
+ return sym.ip < start;
+ }
+
+ bool operator> (const symbol &sym) const {
+ return sym.ip > end;
+ }
+};
class symbol_parser {
private:
@@ -159,6 +141,4 @@ public:
int user_symbol;
};
-extern symbol_parser g_symbol_parser;
-
-#endif
+extern symbol_parser g_symbol_parser; \ No newline at end of file
diff --git a/source/ucli_py/libunwind/unwind.cc b/source/ucli_py/libunwind/unwind.cc
new file mode 100644
index 0000000..fa2a972
--- /dev/null
+++ b/source/ucli_py/libunwind/unwind.cc
@@ -0,0 +1,131 @@
+#include "unwind.h"
+
+#include <errno.h>
+#include <stdio.h>
+
+#include <string>
+
+static std::string unknow_symbol("UNKNOWN");
+
+static int unwind_frame_callback(struct unwind_entry *entry, void *arg) {
+ //! todo: 未实现
+ symbol sym;
+ std::string symbol; // Use std::string instead of string
+ elf_file file;
+
+ sym.reset(entry->ip);
+
+ if (g_symbol_parser.find_symbol_in_cache(entry->pid, entry->ip, symbol)) {
+ printf("#~ 0x%lx %s ([symbol])\n", entry->ip, symbol.c_str());
+ return 0;
+ }
+
+ if (g_symbol_parser.get_symbol_info(entry->pid, sym, file)) {
+ if (g_symbol_parser.find_elf_symbol(sym, file, entry->pid, entry->pid_ns)) {
+ printf("#~ 0x%lx %s ([symbol])\n", entry->ip, sym.name.c_str());
+ g_symbol_parser.putin_symbol_cache(entry->pid, entry->ip, sym.name);
+ } else {
+ printf("#~ 0x%lx %s ([symbol])\n", entry->ip, "(unknown)[symbol]");
+ g_symbol_parser.putin_symbol_cache(entry->pid, entry->ip, unknow_symbol);
+ }
+ } else {
+ printf("#~ 0x%lx %s ([symbol])\n", entry->ip, "(unknown)[vma,elf]");
+ g_symbol_parser.putin_symbol_cache(entry->pid, entry->ip, unknow_symbol);
+ }
+
+ return 0;
+}
+/*
+ * Optimization point.
+ */
+static int reg_value(unw_word_t *valp, struct regs_dump *regs, int id) {
+ /* we only support 3 registers. RIP, RSP and RBP */
+ if (id < 0 || id > 2) return -EINVAL;
+
+ *valp = regs->regs[id];
+ return 0;
+}
+
+static int entry(u64 ip, int pid, int pid_ns, unwind_entry_cb_t cb, void *arg) {
+ struct unwind_entry e;
+
+ e.ip = ip;
+ e.pid = pid;
+ e.pid_ns = pid_ns;
+
+ return cb(&e, arg);
+}
+
+static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb,
+ void *arg) {
+ unw_addr_space_t addr_space;
+ unw_cursor_t c;
+ entry_cb_arg_t *cb_arg = (entry_cb_arg_t *)arg;
+ int ret;
+ int loops = 0;
+
+ addr_space = unw_create_addr_space(&accessors, 0);
+ if (!addr_space) {
+ // pr_err("unwind: Can't create unwind address space.\n");
+ return -ENOMEM;
+ }
+
+ unw_set_caching_policy(addr_space, UNW_CACHE_GLOBAL);
+
+ ret = unw_init_remote(&c, addr_space, ui); /* @ui is args */
+
+ while (!ret && (unw_step(&c) > 0)) {
+ unw_word_t ip;
+
+ unw_get_reg(&c, UNW_REG_IP, &ip); // get IP from current step;
+ cb_arg->arg = &c;
+ ret = entry(ip, ui->pid, ui->pid_ns, cb, cb_arg);
+
+ loops++;
+ if (loops >= 50) break;
+ }
+
+ unw_destroy_addr_space(addr_space);
+ return ret;
+}
+
+int unwind__get_entries(unwind_entry_cb_t cb, void *arg, symbol_parser *sp,
+ int pid, int pid_ns, struct perf_sample *data) {
+ unw_word_t ip;
+ struct unwind_info ui = {
+ .sample = data,
+ .pid = pid,
+ .pid_ns = pid_ns,
+ .sp = sp,
+ };
+ int ret;
+
+ if (!data->user_regs.regs) return -EINVAL;
+
+ ret = reg_value(&ip, &data->user_regs, PERF_REG_IP);
+ if (ret) return ret;
+
+ ret = entry(ip, pid, pid_ns, cb, arg);
+ if (ret) return -ENOMEM;
+
+ return get_entries(&ui, cb, arg);
+}
+
+void diag_printf_raw_stack(int pid, int ns_pid, const char *comm,
+ raw_stack_detail *raw_stack, int attach) {
+ struct perf_sample stack_sample;
+ entry_cb_arg_t unwind_arg;
+ static u64 regs_buf[3];
+
+ printf(" 用户态堆栈SP:%lx, BP:%lx, IP:%lx\n", raw_stack->sp,
+ raw_stack->bp, raw_stack->ip);
+ stack_sample.user_stack.offset = 0;
+ stack_sample.user_stack.size = raw_stack->stack_size;
+ stack_sample.user_stack.data = (char *)&raw_stack->stack[0];
+ stack_sample.user_regs.regs = regs_buf;
+ stack_sample.user_regs.regs[PERF_REG_IP] = raw_stack->ip;
+ stack_sample.user_regs.regs[PERF_REG_SP] = raw_stack->sp;
+ stack_sample.user_regs.regs[PERF_REG_BP] = raw_stack->bp;
+ unwind__get_entries(unwind_frame_callback, &unwind_arg, &g_symbol_parser, pid,
+ ns_pid, &stack_sample);
+} \ No newline at end of file
diff --git a/source/ucli_py/libunwind/unwind.h b/source/ucli_py/libunwind/unwind.h
new file mode 100644
index 0000000..7c5623a
--- /dev/null
+++ b/source/ucli_py/libunwind/unwind.h
@@ -0,0 +1,103 @@
+#include <libunwind-ptrace.h>
+#include <libunwind.h>
+#include <linux/ptrace.h>
+
+#include "symbol.h"
+
+#define DIAG_USER_STACK_SIZE (16 * 1024)
+
+typedef unsigned long u64;
+typedef unsigned char u8;
+typedef unsigned int u32;
+typedef long s64;
+typedef char s8;
+typedef int s32;
+
+typedef struct {
+ struct pt_regs regs;
+ unsigned long ip;
+ unsigned long bp;
+ unsigned long sp;
+ unsigned long stack_size;
+ unsigned long stack[DIAG_USER_STACK_SIZE / sizeof(unsigned long)];
+} raw_stack_detail;
+
+struct regs_dump {
+ u64 *regs;
+};
+
+struct ip_callchain {
+ u64 nr;
+ u64 ips[0];
+};
+
+struct branch_flags {
+ u64 mispred : 1;
+ u64 predicted : 1;
+ u64 reserved : 62;
+};
+
+struct branch_entry {
+ u64 from;
+ u64 to;
+ struct branch_flags flags;
+};
+
+struct branch_stack {
+ u64 nr;
+ struct branch_entry entries[0];
+};
+
+struct stack_dump {
+ unsigned short offset;
+ u64 size;
+ char *data;
+};
+
+struct perf_sample {
+ u64 ip;
+ u32 pid, tid;
+ u64 time;
+ u64 addr;
+ u64 id;
+ u64 stream_id;
+ u64 period;
+ u32 cpu;
+ u32 raw_size;
+ void *raw_data;
+ struct ip_callchain *callchain;
+ struct branch_stack *branch_stack;
+ struct regs_dump user_regs;
+ struct stack_dump user_stack;
+};
+
+#define PERF_REG_IP 0
+#define PERF_REG_SP 1
+#define PERF_REG_BP 2
+
+struct unwind_entry {
+ int pid;
+ int pid_ns;
+ u64 ip;
+ struct vma *map;
+};
+
+typedef struct {
+ struct perf_sample *stack_sample;
+ void *arg;
+} entry_cb_arg_t;
+
+typedef int (*unwind_entry_cb_t)(struct unwind_entry *entry, void *arg);
+
+// unw_create_addr_space need
+extern unw_accessors_t accessors;
+
+struct unwind_info {
+ struct perf_sample *sample;
+ int pid;
+ int pid_ns;
+ symbol_parser *sp;
+};
+
+void diag_printf_raw_stack(int pid, int ns_pid, const char *comm,
+ raw_stack_detail *raw_stack, int attach); \ No newline at end of file
diff --git a/source/ucli_py/unwind/Makefile b/source/ucli_py/unwind/Makefile
deleted file mode 100644
index 56df97f..0000000
--- a/source/ucli_py/unwind/Makefile
+++ /dev/null
@@ -1,29 +0,0 @@
-# Specify the compiler
-CXX=g++
-
-# Specify the target
-TARGET=libunwind.so
-
-# List of source files
-SRCS=symbol.cc unwind.cc
-
-# List of object files
-OBJS=$(SRCS:.cc=.o)
-
-# Compilation flags
-CXXFLAGS=-fPIC -c -Wall
-
-# Default target
-all: $(TARGET)
-
-# Rule to link the target
-$(TARGET): $(OBJS)
- $(CXX) -shared -o $@ $^
-
-# Rule to compile source files
-%.o: %.cc
- $(CXX) $(CXXFLAGS) $< -o $@
-
-# Rule to clean intermediate files
-clean:
- rm -f $(OBJS) $(TARGET) \ No newline at end of file
diff --git a/source/ucli_py/unwind/elf.cc b/source/ucli_py/unwind/elf.cc
deleted file mode 100644
index b4901e2..0000000
--- a/source/ucli_py/unwind/elf.cc
+++ /dev/null
@@ -1,566 +0,0 @@
-/*
- * Linux内核诊断工具--elf相关公共函数
- *
- * Copyright (C) 2020 Alibaba Ltd.
- *
- * License terms: GNU General Public License (GPL) version 3
- *
- */
-
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <elf.h>
-#include <libelf.h>
-#include <gelf.h>
-#include <string.h>
-#include <stdio.h>
-#include <errno.h>
-#include <stdio.h>
-
-#include "elf.h"
-#include "attach.h"
-#include "internal.h"
-
-#define NOTE_ALIGN(n) (((n) + 3) & -4U)
-
-struct sym_section_ctx {
- Elf_Data *syms;
- Elf_Data *symstrs;
- Elf_Data *rel_data;
- int is_reloc;
- int is_plt;
- int sym_count;
- int plt_rel_type;
- unsigned long plt_offset;
- unsigned long plt_entsize;
-};
-
-struct symbol_sections_ctx {
- sym_section_ctx symtab;
- sym_section_ctx symtab_in_dynsym;
- sym_section_ctx dynsymtab;
-};
-
-struct section_info {
- Elf_Scn *sec;
- GElf_Shdr *hdr;
-};
-
-struct plt_ctx {
- section_info dynsym;
- section_info plt_rel;
- section_info plt;
-};
-
-__attribute__((unused)) static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
- GElf_Shdr *shp, const char *name,
- size_t *idx) {
- Elf_Scn *sec = NULL;
- size_t cnt = 1;
-
- /* Elf is corrupted/truncated, avoid calling elf_strptr. */
- if (!elf_rawdata(elf_getscn(elf, ep->e_shstrndx), NULL))
- return NULL;
-
- while ((sec = elf_nextscn(elf, sec)) != NULL) {
- char *str;
-
- gelf_getshdr(sec, shp);
- str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name);
-
- if (!strcmp(name, str)) {
- if (idx)
- *idx = cnt;
-
- break;
- }
-
- ++cnt;
- }
-
- return sec;
-}
-
-__attribute__((unused)) static int elf_read_build_id(Elf *elf, char *bf, size_t size) {
- int err = -1;
- GElf_Ehdr ehdr;
- GElf_Shdr shdr;
- Elf_Data *data;
- Elf_Scn *sec;
- Elf_Kind ek;
- char *ptr;
-
- if (size < BUILD_ID_SIZE)
- goto out;
-
- ek = elf_kind(elf);
-
- if (ek != ELF_K_ELF)
- goto out;
-
- if (gelf_getehdr(elf, &ehdr) == NULL) {
- fprintf(stderr, "%s: cannot get elf header.\n", __func__);
- goto out;
- }
-
- /*
- * Check following sections for notes:
- * '.note.gnu.build-id'
- * '.notes'
- * '.note' (VDSO specific)
- */
- do {
- sec = elf_section_by_name(elf, &ehdr, &shdr,
- ".note.gnu.build-id", NULL);
-
- if (sec)
- break;
-
- sec = elf_section_by_name(elf, &ehdr, &shdr,
- ".notes", NULL);
-
- if (sec)
- break;
-
- sec = elf_section_by_name(elf, &ehdr, &shdr,
- ".note", NULL);
-
- if (sec)
- break;
-
- return err;
-
- } while (0);
-
- data = elf_getdata(sec, NULL);
-
- if (data == NULL)
- goto out;
-
- ptr = (char *)data->d_buf;
-
- while ((intptr_t)ptr < (intptr_t)((char *)data->d_buf + data->d_size)) {
- GElf_Nhdr *nhdr = (GElf_Nhdr *)ptr;
- size_t namesz = NOTE_ALIGN(nhdr->n_namesz),
- descsz = NOTE_ALIGN(nhdr->n_descsz);
- const char *name;
-
- ptr += sizeof(*nhdr);
- name = (const char *)ptr;
- ptr += namesz;
-
- if (nhdr->n_type == NT_GNU_BUILD_ID &&
- nhdr->n_namesz == sizeof("GNU")) {
- if (memcmp(name, "GNU", sizeof("GNU")) == 0) {
- size_t sz = size < descsz ? size : descsz;
- memcpy(bf, ptr, sz);
- memset(bf + sz, 0, size - sz);
- err = descsz;
- break;
- }
- }
-
- ptr += descsz;
- }
-
-out:
- return err;
-}
-
-extern int calc_sha1_1M(const char *filename, unsigned char *buf);
-
-int filename__read_build_id(int pid, const char *mnt_ns_name, const char *filename, char *bf, size_t size) {
- int fd, err = -1;
- struct stat sb;
-
- if (size < BUILD_ID_SIZE)
- goto out;
-
- fd = open(filename, O_RDONLY);
-
- if (fd < 0)
- goto out;
-
- if (fstat(fd, &sb) == 0) {
- snprintf(bf, size, "%s[%lu]", filename, sb.st_size);
- err = 0;
- }
-
- close(fd);
-out:
- return err;
-}
-
-static int is_function(const GElf_Sym *sym)
-{
- return GELF_ST_TYPE(sym->st_info) == STT_FUNC &&
- sym->st_name != 0 &&
- sym->st_shndx != SHN_UNDEF;
-}
-
-static int get_symbols_in_section(sym_section_ctx *sym, Elf *elf, Elf_Scn *sec, GElf_Shdr *shdr, int is_reloc)
-{
- sym->syms = elf_getdata(sec, NULL);
- if (!sym->syms) {
- return -1;
- }
-
- Elf_Scn *symstrs_sec = elf_getscn(elf, shdr->sh_link);
- if (!sec) {
- return -1;
- }
-
- sym->symstrs = elf_getdata(symstrs_sec, NULL);
- if (!sym->symstrs) {
- return -1;
- }
-
- sym->sym_count = shdr->sh_size / shdr->sh_entsize;
- sym->is_plt = 0;
- sym->is_reloc = is_reloc;
-
- return 0;
-}
-
-static int get_plt_symbols_in_section(sym_section_ctx *sym, Elf *elf, plt_ctx *plt)
-{
- sym->syms = elf_getdata(plt->dynsym.sec, NULL);
- if (!sym->syms) {
- return -1;
- }
-
- sym->rel_data = elf_getdata(plt->plt_rel.sec, NULL);
- if (!sym->rel_data) {
- return -1;
- }
-
- Elf_Scn *symstrs_sec = elf_getscn(elf, plt->dynsym.hdr->sh_link);
- if (!symstrs_sec) {
- return -1;
- }
-
- sym->symstrs = elf_getdata(symstrs_sec, NULL);
- if (!sym->symstrs) {
- return -1;
- }
-
- sym->is_plt = 1;
- sym->plt_entsize = plt->plt.hdr->sh_type;
- sym->plt_offset = plt->plt.hdr->sh_offset;
- sym->sym_count = plt->plt_rel.hdr->sh_size / plt->plt_rel.hdr->sh_entsize;
- sym->plt_rel_type = plt->plt_rel.hdr->sh_type;
-
- return 0;
-}
-
-static void __get_plt_symbol(std::set<symbol> &ss, symbol_sections_ctx *si, Elf *elf)
-{
- symbol s;
- GElf_Sym sym;
- int symidx;
- int index = 0;
- const char *sym_name = NULL;
-
- s.end = 0;
- s.start = 0;
-
- if (!si->dynsymtab.syms) {
- return;
- }
-
- while (index < si->dynsymtab.sym_count) {
- if (si->dynsymtab.plt_rel_type == SHT_RELA) {
- GElf_Rela pos_mem, *pos;
- pos = gelf_getrela(si->dynsymtab.rel_data, index, &pos_mem);
- symidx = GELF_R_SYM(pos->r_info);
- }
- else if (si->dynsymtab.plt_rel_type == SHT_REL) {
- GElf_Rel pos_mem, *pos;
- pos = gelf_getrel(si->dynsymtab.rel_data, index, &pos_mem);
- symidx = GELF_R_SYM(pos->r_info);
- }
- else {
- return;
- }
- index++;
- si->dynsymtab.plt_offset += si->dynsymtab.plt_entsize;
- gelf_getsym(si->dynsymtab.syms, symidx, &sym);
-
- sym_name = (const char *)si->dynsymtab.symstrs->d_buf + sym.st_name;
- s.start = si->dynsymtab.plt_offset;
- s.end = s.start + si->dynsymtab.plt_entsize;
- s.ip = s.start;
- s.name = sym_name;
- ss.insert(s);
- }
-}
-
-static void __get_symbol_without_plt(std::set<symbol> &ss, sym_section_ctx *tab, Elf *elf)
-{
- GElf_Sym sym;
- int index = 0;
- const char *sym_name;
- symbol s;
- s.end = 0;
- s.start = 0;
-
- while (index < tab->sym_count) {
- gelf_getsym(tab->syms, index, &sym);
- index++;
- if (sym.st_shndx == SHN_ABS) {
- continue;
- }
- if (!is_function(&sym)) {
- continue;
- }
- sym_name = (const char *)tab->symstrs->d_buf + sym.st_name;
- if (tab->is_reloc) {
- Elf_Scn *sec = elf_getscn(elf, sym.st_shndx);
- if (!sec) {
- continue;
- }
- GElf_Shdr shdr;
- gelf_getshdr(sec, &shdr);
- sym.st_value -= shdr.sh_addr - shdr.sh_offset;
- }
- s.start = sym.st_value & 0xffffffff;
- s.end = s.start + sym.st_size;
- s.ip = s.start;
- s.name = sym_name;
- ss.insert(s);
- }
-}
-
-static void __get_symbol(std::set<symbol> &ss, symbol_sections_ctx *si, Elf *elf)
-{
- symbol s;
- s.end = 0;
- s.start = 0;
-
- if (!si->symtab.syms && !si->dynsymtab.syms) {
- return;
- }
-
- sym_section_ctx *tab = &si->symtab;
- __get_symbol_without_plt(ss, tab, elf);
- tab = &si->symtab_in_dynsym;
- __get_symbol_without_plt(ss, tab, elf);
-}
-
-static void get_all_symbols(std::set<symbol> &ss, symbol_sections_ctx *si, Elf *elf)
-{
- __get_symbol(ss, si, elf);
- __get_plt_symbol(ss, si, elf);
-}
-
-bool search_symbol(const std::set<symbol> &ss, symbol &sym)
-{
- std::set<symbol>::const_iterator it = ss.find(sym);
-
- if (it != ss.end()) {
- sym.end = it->end;
- sym.start = it->start;
- sym.name = it->name;
-
- return true;
- }
-
- return false;
-}
-
-bool get_symbol_from_elf(std::set<symbol> &ss, const char *path)
-{
- static int first_init = 0;
-
- if (!first_init) {
- first_init = true;
- init_global_env();
- }
-
- int is_reloc = 0;
- elf_version(EV_CURRENT);
- int fd = open(path, O_RDONLY);
-
- Elf *elf = elf_begin(fd, ELF_C_READ, NULL);
- if (elf == NULL) {
- close(fd);
- return false;
- }
-
- Elf_Kind ek = elf_kind(elf);
- if (ek != ELF_K_ELF) {
- elf_end(elf);
- close(fd);
- return false;
- }
- GElf_Ehdr hdr;
- if (gelf_getehdr(elf, &hdr) == NULL) {
- elf_end(elf);
- close(fd);
- return false;
- }
-
- if (hdr.e_type == ET_EXEC) {
- is_reloc = 1;
- }
-
- if (!elf_rawdata(elf_getscn(elf, hdr.e_shstrndx), NULL)) {
- elf_end(elf);
- close(fd);
- return false;
- }
-
- GElf_Shdr shdr;
- GElf_Shdr symtab_shdr;
- GElf_Shdr dynsym_shdr;
- GElf_Shdr plt_shdr;
- GElf_Shdr plt_rel_shdr;
- memset(&shdr, 0, sizeof(shdr));
- memset(&symtab_shdr, 0, sizeof(symtab_shdr));
- memset(&dynsym_shdr, 0, sizeof(dynsym_shdr));
- memset(&plt_shdr, 0, sizeof(plt_shdr));
- memset(&plt_rel_shdr, 0, sizeof(plt_rel_shdr));
-
- Elf_Scn *sec = NULL;
- Elf_Scn *dynsym_sec = NULL;
- Elf_Scn *symtab_sec = NULL;
- Elf_Scn *plt_sec = NULL;
- Elf_Scn *plt_rel_sec = NULL;
-
- while ((sec = elf_nextscn(elf, sec)) != NULL) {
- char *str;
- gelf_getshdr(sec, &shdr);
- str = elf_strptr(elf, hdr.e_shstrndx, shdr.sh_name);
-
- if (str && strcmp(".symtab", str) == 0) {
- symtab_sec = sec;
- memcpy(&symtab_shdr, &shdr, sizeof(dynsym_shdr));
- }
- if (str && strcmp(".dynsym", str) == 0) {
- dynsym_sec = sec;
- memcpy(&dynsym_shdr, &shdr, sizeof(dynsym_shdr));
- }
- if (str && strcmp(".rela.plt", str) == 0) {
- plt_rel_sec = sec;
- memcpy(&plt_rel_shdr, &shdr, sizeof(plt_rel_shdr));
- }
- if (str && strcmp(".plt", str) == 0) {
- plt_sec = sec;
- memcpy(&plt_shdr, &shdr, sizeof(plt_shdr));
- }
- if (str && strcmp(".gnu.prelink_undo", str) == 0) {
- is_reloc = 1;
- }
- }
-
- plt_ctx plt;
- plt.dynsym.hdr = &dynsym_shdr;
- plt.dynsym.sec = dynsym_sec;
- plt.plt.hdr = &plt_shdr;
- plt.plt.sec = plt_sec;
- plt.plt_rel.hdr = &plt_rel_shdr;
- plt.plt_rel.sec = plt_rel_sec;
-
- symbol_sections_ctx si;
- memset(&si, 0, sizeof(si));
- if (symtab_sec) {
- get_symbols_in_section(&si.symtab, elf, symtab_sec, &symtab_shdr, is_reloc);
- }
- if (dynsym_sec) {
- get_symbols_in_section(&si.symtab_in_dynsym, elf, dynsym_sec, &dynsym_shdr, is_reloc);
- }
- if (dynsym_sec && plt_sec) {
- get_plt_symbols_in_section(&si.dynsymtab, elf, &plt);
- }
-
- get_all_symbols(ss, &si, elf);
- elf_end(elf);
- close(fd);
- return true;
-}
-
-struct symbol_cache_item {
- int start;
- int size;
- char name[0];
-};
-
-bool save_symbol_cache(std::set<symbol> &ss, const char *path)
-{
- char buf[2048];
- int len = 0;
- bool status = true;
-
- int fd = open(path, O_RDONLY);
- if (fd < 0) {
- status = false;
- return status;
- }
- int ret;
- ret = read(fd, &len, 4);
- if (ret <= 0) {
- close(fd);
- status = false;
- return status;
- }
- ret = read(fd, buf, len);
- if (ret <= 0) {
- close(fd);
- status = false;
- return status;
- }
-
- while (1) {
- struct symbol_cache_item *sym;
- symbol s;
- ret = read(fd, &len, 4);
- if (ret <= 0) {
- status = false;
- break;
- }
- ret = read(fd, buf, len);
- if (ret < len) {
- status = false;
- break;
- }
- sym = (struct symbol_cache_item *)buf;
- s.start = sym->start;
- s.end = sym->start + sym->size;
- s.ip = sym->start;
- s.name = sym->name;
- ss.insert(s);
- }
- close(fd);
- return status;
-}
-
-bool load_symbol_cache(std::set<symbol> &ss, const char *path, const char *filename)
-{
- int fd = open(path, O_RDWR | O_EXCL);
- if (fd < 0) {
- return false;
- }
- int len = strlen(filename);
- int ret = write(fd, &len, 4);
- if (ret < 0) {
- close(fd);
- return false;
- }
- ret = write(fd, filename, len);
- if (ret < 0) {
- close(fd);
- return false;
- }
-
- std::set<symbol>::iterator it;
- int v;
- for (it = ss.begin(); it != ss.end(); ++it) {
- v = it->start;
- ret = write(fd, &v, 4);
- v = it->end - it->start;
- ret = write(fd, &v, 4);
- ret = write(fd, it->name.c_str(), it->name.length());
- }
- return true;
-}
diff --git a/source/ucli_py/unwind/elf.h b/source/ucli_py/unwind/elf.h
deleted file mode 100644
index 7e02c0e..0000000
--- a/source/ucli_py/unwind/elf.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Linux内核诊断工具--elf相关函数头文件
- *
- * Copyright (C) 2020 Alibaba Ltd.
- *
- * License terms: GNU General Public License (GPL) version 3
- *
- */
-
-#ifndef _PERF_ELF_H__
-#define _PERF_ELF_H__
-
-#include <set>
-#include <string>
-
-#include "symbol.h"
-
-#define BUILD_ID_SIZE 40
-bool save_symbol_cache(std::set<symbol> &ss, const char *path);
-bool load_symbol_cache(std::set<symbol> &ss, const char *path, const char *filename);
-
-bool get_symbol_from_elf(std::set<symbol> &ss, const char *path);
-bool search_symbol(const std::set<symbol> &ss, symbol &sym);
-int filename__read_build_id(int pid, const char *mnt_ns_name, const char *filename, char *bf, size_t size);
-#endif
diff --git a/source/ucli_py/unwind/internal.h b/source/ucli_py/unwind/internal.h
deleted file mode 100644
index 9139e1e..0000000
--- a/source/ucli_py/unwind/internal.h
+++ /dev/null
@@ -1,189 +0,0 @@
-// /*
-// * Linux内核诊断工具--杂项定义头文件
-// *
-// * Copyright (C) 2020 Alibaba Ltd.
-// *
-// * 作者: Baoyou Xie <[email protected]>
-// *
-// * License terms: GNU General Public License (GPL) version 3
-// *
-// */
-
-// #include <string>
-// #include <set>
-// #include "uapi/ali_diagnose.h"
-// #include "json/json.h"
-
-// #include <fcntl.h>
-// #include <sys/ioctl.h>
-// #include <unistd.h>
-
-// #include "debug.h"
-
-// extern std::set<int> g_proc_map;
-
-// int run_trace_main(int argc, char **argv);
-// int sys_delay_main(int argc, char **argv);
-// int sched_delay_main(int argc, char **argv);
-// int throttle_delay_main(int argc, char **argv);
-// int load_monitor_main(int argc, char **argv);
-// int exit_monitor_main(int argc, char **argv);
-// int utilization_main(int argc, char **argv);
-// int perf_main(int argc, char **argv);
-// int tcp_retrans_main(int argc, char **argv);
-// int tcp_connect_main(int argc, char **argv);
-// int rw_top_main(int argc, char **argv);
-// int irq_delay_main(int argc, char **argv);
-// int mutex_monitor_main(int argc, char **argv);
-// int alloc_top_main(int argc, char **argv);
-// int alloc_load_main(int argc, char **argv);
-// int drop_packet_main(int argc, char **argv);
-// int fs_orphan_main(int argc, char **argv);
-// int df_du_main(int argc, char **argv);
-// int exec_monitor_main(int argc, char **argv);
-// int fs_shm_main(int argc, char **argv);
-// int irq_stats_main(int argc, char **argv);
-// int irq_trace_main(int argc, char **argv);
-// int kprobe_main(int argc, char **argv);
-// int mm_leak_main(int argc, char **argv);
-// int proc_monitor_main(int argc, char **argv);
-// int runq_info_main(int argc, char **argv);
-// int reboot_main(int argc, char **argv);
-// int pi_main(int argc, char *argv[]);
-// int memcpy_main(int argc, char* argv[]);
-// int md5_main(int argc, char *argv[]);
-// int net_bandwidth_main(int argc, char *argv[]);
-// int sig_info_main(int argc, char *argv[]);
-// int task_monitor_main(int argc, char **argv);
-// int rw_sem_main(int argc, char **argv);
-// int rss_monitor_main(int argc, char **argv);
-
-// void usage_run_trace(void);
-// void usage_sys_delay(void);
-// void usage_load_monitor(void);
-// void usage_exit_monitor(void);
-// void usage_utilization(void);
-// void usage_perf();
-// void usage_tcp_retrans();
-// void usage_rw_top();
-// void usage_irq_delay();
-// void usage_mutex_monitor();
-// void usage_alloc_top();
-// void usage_drop_packet();
-// void usage_fs_orphan();
-// void usage_exec_monitor();
-// void usage_fs_shm();
-// void usage_irq_stats();
-// void usage_irq_trace();
-// void usage_kprobe();
-// void usage_mm_leak();
-// void usage_testcase(void);
-// void usage_pupil(void);
-// void usage_sched_delay(void);
-// void usage_reboot(void);
-// void usage_test_memcpy(void);
-// void usage_test_pi(void);
-// void usage_test_md5(void);
-// void usage_net_bandwidth(void);
-// void usage_sig_info(void);
-// void usage_task_monitor(void);
-// void usage_rw_sem(void);
-// void usage_rss_monitor(void);
-// void usage_throttle_delay(void);
-
-// int uprobe_main(int argc, char **argv);
-// void usage_uprobe();
-
-// int ping_delay_main(int argc, char *argv[]);
-// void usage_ping_delay(void);
-// int ping_delay6_main(int argc, char *argv[]);
-// void usage_ping_delay6(void);
-
-// int test_run_trace_main(int argc, char *argv[]);
-// void usage_test_run_trace(void);
-
-// int memcg_stats_main(int argc, char *argv[]);
-// void usage_memcg_stats(void);
-
-// int diag_activate(const char func[]);
-// int diag_deactivate(const char func[]);
-
-// void diag_printf_inode(struct diag_inode_detail *inode);
-// void diag_printf_time(struct diag_timespec *tv);
-// void diag_printf_task(struct diag_task_detail *task);
-// void diag_printf_proc_chains(struct diag_proc_chains_detail *proc_chains);
-// void diag_printf_proc_chains(struct diag_proc_chains_detail *proc_chains, int reverse);
-// void diag_printf_proc_chains(struct diag_proc_chains_detail *proc_chains, int reverse, int detail);
-// void diag_printf_kern_stack(struct diag_kern_stack_detail *kern_stack);
-// void diag_printf_kern_stack(struct diag_kern_stack_detail *kern_stack, int reverse);
-// void diag_printf_user_stack(int pid, int ns_pid, const char *comm,
-// struct diag_user_stack_detail *user_stack);
-// void diag_printf_user_stack(int pid, int ns_pid, const char *comm,
-// struct diag_user_stack_detail *user_stack, int attach);
-// void diag_printf_user_stack(int pid, int ns_pid, const char *comm,
-// struct diag_user_stack_detail *user_stack, int attach, int reverse);
-// void diag_printf_raw_stack(int pid, int ns_pid, const char *comm,
-// struct diag_raw_stack_detail *raw_stack);
-// void diag_printf_raw_stack(int pid, int ns_pid, const char *comm,
-// struct diag_raw_stack_detail *raw_stack, int attach);
-// void init_java_env(const char *agent, int pid, int ns_pid, const char *comm, std::set<int> &);
-// void diag_unwind_raw_stack(int pid, int ns_pid,
-// struct diag_raw_stack_detail *raw_stack, unsigned long stack[BACKTRACE_DEPTH]);
-
-// void diag_sls_time(struct diag_timespec *tv, Json::Value &owner);
-// void diag_sls_task(struct diag_task_detail *tsk_info, Json::Value &task);
-// void diag_sls_proc_chains(struct diag_proc_chains_detail *proc_chains, Json::Value &task);
-// void diag_sls_kern_stack(struct diag_kern_stack_detail *kern_stack, Json::Value &task);
-// void diag_sls_user_stack(pid_t pid, pid_t ns_pid, const char *comm,
-// struct diag_user_stack_detail *user_stack, Json::Value &task);
-// void diag_sls_user_stack(pid_t pid, pid_t ns_pid, const char *comm,
-// struct diag_user_stack_detail *user_stack, Json::Value &task, int attach);
-// void diag_sls_inode(struct diag_inode_detail *inode, Json::Value &root);
-// int log_config(char *arg, char *sls_file, int *p_syslog_enabled);
-// void write_syslog(int enabled, const char mod[], struct diag_timespec *tv, unsigned long id, int seq, Json::Value &root);
-// void write_file(char *sls_file, const char mod[], struct diag_timespec *tv, unsigned long id, int seq, Json::Value &root);
-// void diag_ip_addr_to_str(unsigned char *ip_addr,const char type[], Json::Value &root);
-// #define ULONG_MAX (~0UL)
-// #define STACK_IS_END(v) ((v) == 0 || (v) == ULONG_MAX)
-
-// class pid_cmdline {
-// private:
-// std::map<int, std::string> cmdlines;
-// public:
-// void clear(void);
-// std::string & get_pid_cmdline(int pid);
-// };
-
-// int jmaps_main(int argc, char **argv);
-// void restore_global_env();
-// int attach_ns_env(int pid);
-// int java_attach_once(int flag_no_attach = 0);
-
-// extern class pid_cmdline pid_cmdline;
-
-// extern void clear_symbol_info(class pid_cmdline &pid_cmdline, std::set<int> &procs, int dist);
-// extern unsigned int ipstr2int(const char *ipstr);
-// extern char *int2ipstr(const unsigned int ip, char *ipstr, const unsigned int ip_str_len);
-
-// extern int is_linux_2_6_x(void);
-// extern int linux_2_6_x;
-
-// int sys_cost_main(int argc, char **argv);
-// void usage_sys_cost();
-
-// int fs_cache_main(int argc, char *argv[]);
-// void usage_fs_cache(void);
-
-// int high_order_main(int argc, char *argv[]);
-// void usage_high_order(void);
-
-// int pmu_main(int argc, char **argv);
-// void usage_pmu(void);
-
-// int testcase_main(int argc, char *argv[]);
-
-// struct timeval;
-// struct timezone;
-// extern "C" {
-// void diag_gettimeofday(struct diag_timespec *tv, struct timezone *tz);
-// }
diff --git a/source/ucli_py/unwind/symbol.cc b/source/ucli_py/unwind/symbol.cc
deleted file mode 100644
index dac1680..0000000
--- a/source/ucli_py/unwind/symbol.cc
+++ /dev/null
@@ -1,504 +0,0 @@
-/*
- * Linux内核诊断工具--用户态符号表解析
- *
- * Copyright (C) 2020 Alibaba Ltd.
- *
- * License terms: GNU General Public License (GPL) version 3
- *
- */
-
-#include <vector>
-#include <string.h>
-#include <algorithm>
-
-#include "symbol.h"
-#include "elf.h"
-#include "internal.h"
-
-void restore_global_env();
-int attach_ns_env(int pid);
-
-symbol_parser g_symbol_parser;
-
-bool symbol_parser::add_pid_maps(int pid, size_t start, size_t end, size_t offset, const char *name)
-{
- std::map<int, proc_vma>::iterator it;
- it = machine_vma.find(pid);
- if (it == machine_vma.end()) {
- proc_vma proc;
- machine_vma.insert(make_pair(pid, proc));
- it = machine_vma.find(pid);
- if (it == machine_vma.end()) {
- return false;
- }
- }
-
- vma vm(start, end, offset, name);
- it->second.insert(std::make_pair(vm.start, std::move(vm)));
-
- return true;
-}
-
-bool symbol_parser::load_pid_maps(int pid)
-{
- std::map<int, proc_vma>::iterator it;
- it = machine_vma.find(pid);
- if (it != machine_vma.end()) {
- return true;
- }
-
- proc_vma proc;
- char fn[256];
- sprintf(fn, "/proc/%d/maps", pid);
- FILE *fp = fopen(fn, "r");
- if (!fp) {
- return false;
- }
-
- char buf[4096];
- char exename[4096];
- size_t start, end, offset;
- while (fgets(buf, sizeof(buf), fp) != NULL) {
- start = end = offset = 0;
- exename[0] = '\0';
- sscanf(buf, "%lx-%lx %*s %lx %*x:%*x %*u %s %*s\n", &start, &end, &offset, exename);
- if (exename[0] == '\0') {
- strcpy(exename, "[anon]");
- }
- vma vm(start, end, offset, exename);
- proc.insert(std::make_pair(vm.start, std::move(vm)));
- }
-
- fclose(fp);
-
- machine_vma.insert(std::make_pair(pid, std::move(proc)));
- it = machine_vma.find(pid);
- if (it == machine_vma.end()) {
- return false;
- }
-
- return true;
-}
-
-bool symbol_parser::load_perf_map(int pid, int pid_ns)
-{
-#if 0
- if (pid != pid_ns) {
- if (attach_ns_env(pid) < 0) {
- return false;
- }
- }
-#endif
- char perfmapfile[64];
- snprintf(perfmapfile, sizeof(perfmapfile), "/tmp/perf-%d.map", pid);
- FILE *fp = fopen(perfmapfile, "r");
- if (fp == NULL) {
- return false;
- }
- char line[256];
- char *buf;
- long start;
- int size;
- char name[256];
- std::set<symbol> syms;
- symbol sym;
- while ((buf = fgets(line, sizeof(line), fp)) != NULL) {
- sscanf(buf, "%lx %x %s\n", &start, &size, name);
- sym.start = start;
- sym.end = sym.start + size;
- sym.ip = sym.start;
- sym.name = name;
- syms.insert(sym);
- }
- java_symbols.insert(make_pair(pid, std::move(syms)));
-#if 0
- if (pid != pid_ns) {
- restore_global_env();
- }
-#endif
- return true;
-}
-
-bool symbol_parser::find_java_symbol(symbol &sym, int pid, int pid_ns)
-{
- std::set<symbol> ss;
- std::map<int, std::set<symbol> >::iterator it;
- //bool load_now = false;
- it = java_symbols.find(pid);
- if (it == java_symbols.end()) {
- if (!load_perf_map(pid, pid_ns)) {
- return false;
- }
- //load_now = true;
- it = java_symbols.find(pid);
- return search_symbol(it->second, sym);
- } else {
- return search_symbol(it->second, sym);
- }
- return true;
-
- //bool ret = search_symbol(syms, sym);
-#if 0
- if (!ret && !load_now) {
- java_symbols.erase(pid);
- if (!load_perf_map(pid)) {
- return false;
- }
- syms = java_symbols.find(pid)->second;
- return search_symbol(syms, sym);
- }
-#endif
- //return ret;
-}
-
-static bool load_kernel_symbol_list(std::vector<std::string> &sym_list)
-{
- FILE *fp = fopen("/proc/kallsyms", "r");
- if (!fp) {
- return -1;
- }
-
- char buf[256];
- char type;
- int len;
- while (fgets(buf, sizeof(buf), fp) != NULL) {
- sscanf(buf, "%*p %c %*s\n", &type);
- if ((type | 0x20) != 't') {
- continue;
- }
- len = strlen(buf);
- if (buf[len-1] == '\n') {
- buf[len-1] = ' ';
- }
- sym_list.push_back(buf);
- }
- fclose(fp);
-
- std::sort(sym_list.begin(), sym_list.end());
- return true;
-}
-
-bool is_space(int ch) {
- return std::isspace(ch);
-}
-
-static inline void rtrim(std::string &s)
-{
- s.erase(std::find_if(s.rbegin(), s.rend(), is_space).base(), s.end());
-}
-
-static bool get_next_kernel_symbol(
- std::set<symbol> &syms,
- std::vector<std::string> &sym_list,
- std::vector<std::string>::iterator cursor)
-{
- if (cursor == sym_list.end()) {
- return false;
- }
- symbol sym;
- size_t start, end;
- sscanf(cursor->c_str(), "%p %*c %*s\n", (void **)&start);
- sym.name = cursor->c_str() + 19;
- rtrim(sym.name);
-#if 0
- if (sym.name[sym.name.size()-1] == '\n') {
- sym.name[sym.name.size()-1] = '\0';
- }
-#endif
- cursor++;
- if (cursor != sym_list.end()) {
- sscanf(cursor->c_str(), "%p %*c %*s\n", (void **)&end);
- }
- else {
- end = INVALID_ADDR;
- }
- sym.start = start;
- sym.end = end;
- sym.ip = start;
-
- syms.insert(sym);
- return true;
-}
-
-bool symbol_parser::load_kernel()
-{
- if (kernel_symbols.size() != 0) {
- return true;
- }
-
- std::vector<std::string> sym_list;
- if (!load_kernel_symbol_list(sym_list)) {
- exit(0);
- return false;
- }
-
- std::vector<std::string>::iterator cursor = sym_list.begin();
- while (get_next_kernel_symbol(kernel_symbols, sym_list, cursor)) {
- cursor++;
- }
- return true;
-}
-
-bool symbol_parser::load_elf(pid_t pid, const elf_file &file)
-{
- std::map<elf_file, std::set<symbol> >::iterator it;
- it = file_symbols.find(file);
- std::set<symbol> tmp;
- std::set<symbol> &syms = tmp;
- if (it != file_symbols.end()) {
- return true;
- }
- if (get_symbol_from_elf(syms, file.filename.c_str())) {
- file_symbols.insert(make_pair(file, std::move(syms)));
- return true;
- }
- return false;
-}
-
-bool symbol_parser::find_kernel_symbol(symbol &sym)
-{
- load_kernel();
- sym.end = sym.start = 0;
- std::set<symbol>::iterator it = kernel_symbols.find(sym);
- if (it != kernel_symbols.end()) {
- sym.end = it->end;
- sym.start = it->start;
- sym.name = it->name;
- return true;
- }
- return false;
-}
-
-bool symbol_parser::find_symbol_in_cache(int tgid, unsigned long addr, std::string &symbol)
-{
- std::map<int, std::map<unsigned long, std::string> >::const_iterator it_pid =
- symbols_cache.find(tgid);
-
- if (it_pid != symbols_cache.end()) {
- std::map<unsigned long, std::string> map = symbols_cache[tgid];
- std::map<unsigned long, std::string>::const_iterator it_symbol =
- map.find(addr);
-
- if (it_symbol != map.end()) {
- symbol = map[addr];
-
- return true;
- }
- }
-
- return false;
-}
-
-bool symbol_parser::putin_symbol_cache(int tgid, unsigned long addr, std::string &symbol)
-{
- std::map<int, std::map<unsigned long, std::string> >::const_iterator it_pid =
- symbols_cache.find(tgid);
-
- if (it_pid == symbols_cache.end()) {
- std::map<unsigned long, std::string> map;
- symbols_cache.insert(std::make_pair(tgid, map));
- }
-
- std::map<unsigned long, std::string> &map = symbols_cache[tgid];
- std::map<unsigned long, std::string>::const_iterator it_symbol =
- map.find(addr);
-
- if (it_symbol == map.end()) {
- map[addr] = symbol;
- return true;
- }
-
- return false;
-}
-
-bool symbol_parser::get_symbol_info(int pid, symbol &sym, elf_file &file)
-{
- std::map<int, proc_vma>::iterator proc_vma_info;
-
- if (java_only) {
- file.type = UNKNOWN;
- return true;
- }
-
- proc_vma_info = machine_vma.find(pid);
- if (proc_vma_info == machine_vma.end()) {
- if (!load_pid_maps(pid)) {
- return false;
- }
- }
-
- vma area(sym.ip);
- if (!find_vma(pid, area)) {
- return false;
- }
- if (area.name == "[anon]") {
- file.type = JIT_TYPE;
- }
-
- file.reset(area.name);
- if (file.type != JIT_TYPE) {
- sym.reset(area.map(sym.ip));
- }
-
- return true;
-}
-
-bool symbol_parser::find_elf_symbol(symbol &sym, const elf_file &file, int pid, int pid_ns)
-{
- if (java_only) {
- return find_java_symbol(sym, pid, pid_ns);
- }
-
- if (file.type == JIT_TYPE) {
- return find_java_symbol(sym, pid, pid_ns);
- }
-
- std::map<elf_file, std::set<symbol> >::iterator it;
- it = file_symbols.find(file);
- std::set<symbol> ss;
- if (it == file_symbols.end()) {
- if (!load_elf(pid, file)) {
- return false;
- }
- it = file_symbols.find(file);
- return search_symbol(it->second, sym);
- } else {
- return search_symbol(it->second, sym);
- }
- return true;
-}
-
-vma* symbol_parser::find_vma(pid_t pid, size_t pc)
-{
- std::map<int, proc_vma>::iterator it;
-
- it = machine_vma.find(pid);
- if (it == machine_vma.end()) {
- return NULL;
- }
-
- proc_vma::iterator vma_iter = it->second.upper_bound(pc);
- if (vma_iter == it->second.end() || vma_iter->second.end < pc) {
- return NULL;
- }
-
- if (vma_iter != it->second.begin()) {
- --vma_iter;
- }
-
- return &vma_iter->second;
-}
-
-bool symbol_parser::find_vma(pid_t pid, vma &vm)
-{
- std::map<int, proc_vma>::iterator proc_vma_map;
-
- proc_vma_map = machine_vma.find(pid);
- if (proc_vma_map == machine_vma.end()) {
- return false;
- }
-
- proc_vma::const_iterator vma_iter = proc_vma_map->second.upper_bound(vm.pc);
- if (vma_iter == proc_vma_map->second.end()) {
- return false;
- }
- if (vma_iter->second.end < vm.pc) {
- return false;
- }
-
- if (vma_iter != proc_vma_map->second.begin()) {
- --vma_iter;
- }
-
- vm.start = vma_iter->second.start;
- vm.end = vma_iter->second.end;
- vm.name = vma_iter->second.name;
- vm.offset = vma_iter->second.offset;
-
- return true;
-}
-
-void clear_symbol_info(class pid_cmdline &pid_cmdline, std::set<int> &procs, int dist)
-{
- pid_cmdline.clear();
- procs.clear();
- g_symbol_parser.clear_symbol_info(dist);
-}
-
-void symbol_parser::clear_symbol_info(int dist)
-{
- machine_vma.clear();
- java_symbols.clear();
- if (dist) {
- kernel_symbols.clear();
- file_symbols.clear();
- }
-}
-
-void symbol_parser::dump(void)
-{
- int count1, count2, count3;
- {
- count1 = 0;
- count2 = 0;
- count3 = 0;
- std::map<elf_file, std::set<symbol> >::iterator iter = file_symbols.begin();
- for(; iter != file_symbols.end(); ++iter) {
- std::set<symbol>& map = iter->second;
- const elf_file& file = iter->first;
-
- count1++;
- printf("xby-debug, file_symbols: %s, %lu\n",
- file.filename.c_str(),
- map.size());
-
- count2 += map.size();
- std::set<symbol>::iterator it = map.begin();
- for(; it != map.end(); ++it) {
- count3 += it->name.length();
- }
- }
- printf("xby-debug, file_symbols: %d, %d, %d\n", count1, count2, count3);
- printf("xby-debug, sizeof(symbol): %ld\n", sizeof(symbol));
- }
-
- {
- count1 = 0;
- count2 = 0;
- std::map<int, std::set<symbol> >::iterator iter = java_symbols.begin();
- for(; iter != java_symbols.end(); ++iter) {
- count1++;
- std::set<symbol>& map = iter->second;
- count2 += map.size();
- }
- printf("xby-debug, java_symbols: %d, %d\n", count1, count2);
- }
-
- {
- printf("xby-debug, kernel_symbols: %lu\n", kernel_symbols.size());
- }
-
- {
- count1 = 0;
- count2 = 0;
- std::map<int, proc_vma>::iterator iter = machine_vma.begin();
- for(; iter != machine_vma.end(); ++iter) {
- count1++;
- proc_vma map = iter->second;
- count2 += map.size();
- }
- printf("xby-debug, machine_vma: %d, %d\n", count1, count2);
- }
-
- {
- count1 = 0;
- count2 = 0;
- std::map<int, std::map<unsigned long, std::string> >::iterator iter = symbols_cache.begin();
- for(; iter != symbols_cache.end(); ++iter) {
- count1++;
- std::map<unsigned long, std::string>& map = iter->second;
- count2 += map.size();
- }
- printf("xby-debug, symbols_cache: %d, %d\n", count1, count2);
- }
-}
diff --git a/source/ucli_py/unwind/unwind.cc b/source/ucli_py/unwind/unwind.cc
deleted file mode 100644
index 85aa4b5..0000000
--- a/source/ucli_py/unwind/unwind.cc
+++ /dev/null
@@ -1,684 +0,0 @@
-/*
- * Post mortem Dwarf CFI based unwinding on top of regs and stack dumps.
- *
- * Lots of this code have been borrowed or heavily inspired from parts of
- * the libunwind 0.99 code which are (amongst other contributors I may have
- * forgotten):
- *
- * Copyright (C) 2002-2007 Hewlett-Packard Co
- * Contributed by David Mosberger-Tang <[email protected]>
- *
- * And the bugs have been added by:
- *
- * Copyright (C) 2010, Frederic Weisbecker <[email protected]>
- * Copyright (C) 2012, Jiri Olsa <[email protected]>
- *
- */
-
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/mman.h>
-
-#include <limits.h>
-#include <string.h>
-#include <errno.h>
-#include <inttypes.h>
-
-//#include <perf_regs.h>
-#include <elf.h>
-#include <gelf.h>
-#include <libunwind.h>
-#include <libunwind-ptrace.h>
-
-
-#include "unwind.h"
-#include "symbol.h"
-
-
-extern "C" {
-int UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as,
- unw_word_t ip,
- unw_dyn_info_t *di,
- unw_proc_info_t *pi,
- int need_unwind_info, void *arg);
-}
-
-#define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table)
-
-#define DW_EH_PE_FORMAT_MASK 0x0f /* format of the encoded value */
-#define DW_EH_PE_APPL_MASK 0x70 /* how the value is to be applied */
-
-/* Pointer-encoding formats: */
-#define DW_EH_PE_omit 0xff
-#define DW_EH_PE_ptr 0x00 /* pointer-sized unsigned value */
-#define DW_EH_PE_udata4 0x03 /* unsigned 32-bit value */
-#define DW_EH_PE_udata8 0x04 /* unsigned 64-bit value */
-#define DW_EH_PE_sdata4 0x0b /* signed 32-bit value */
-#define DW_EH_PE_sdata8 0x0c /* signed 64-bit value */
-
-/* Pointer-encoding application: */
-#define DW_EH_PE_absptr 0x00 /* absolute value */
-#define DW_EH_PE_pcrel 0x10 /* rel. to addr. of encoded value */
-
-/*
- * The following are not documented by LSB v1.3, yet they are used by
- * GCC, presumably they aren't documented by LSB since they aren't
- * used on Linux:
- */
-#define DW_EH_PE_funcrel 0x40 /* start-of-procedure-relative */
-#define DW_EH_PE_aligned 0x50 /* aligned pointer */
-
-/* Flags intentionaly not handled, since they're not needed:
- * #define DW_EH_PE_indirect 0x80
- * #define DW_EH_PE_uleb128 0x01
- * #define DW_EH_PE_udata2 0x02
- * #define DW_EH_PE_sleb128 0x09
- * #define DW_EH_PE_sdata2 0x0a
- * #define DW_EH_PE_textrel 0x20
- * #define DW_EH_PE_datarel 0x30
- */
-
-
-struct unwind_info {
- struct perf_sample *sample;
- int pid;
- int pid_ns;
- symbol_parser *sp;
-};
-
-#define dw_read(ptr, type, end) ({ \
- type *__p = (type *) ptr; \
- type __v; \
- if ((__p + 1) > (type *) end) \
- return -EINVAL; \
- __v = *__p++; \
- ptr = (typeof(ptr)) __p; \
- __v; \
- })
-
-#ifdef __x86_64__
-int unwind__arch_reg_id(int regnum)
-{
- int id;
-
- switch (regnum) {
- case UNW_X86_64_RBP:
- id = PERF_REG_BP;
- break;
- case UNW_X86_64_RSP:
- id = PERF_REG_SP;
- break;
- case UNW_X86_64_RIP:
- id = PERF_REG_IP;
- break;
- default:
- return -EINVAL;
- }
-
- return id;
-}
-#else
-int unwind__arch_reg_id(int regnum)
-{
- int id;
- switch (regnum) {
- case UNW_AARCH64_SP:
- id = PERF_REG_SP;
- break;
- case UNW_AARCH64_PC:
- id = PERF_REG_IP;
- break;
- default:
- return -EINVAL;
- }
-
- return id;
-}
-#endif
-
-static int __dw_read_encoded_value(u8 **p, u8 *end, u64 *val,
- u8 encoding)
-{
- u8 *cur = *p;
- *val = 0;
-
- switch (encoding) {
- case DW_EH_PE_omit:
- *val = 0;
- goto out;
- case DW_EH_PE_ptr:
- *val = dw_read(cur, unsigned long, end);
- goto out;
- default:
- break;
- }
-
- switch (encoding & DW_EH_PE_APPL_MASK) {
- case DW_EH_PE_absptr:
- break;
- case DW_EH_PE_pcrel:
- *val = (unsigned long) cur;
- break;
- default:
- return -EINVAL;
- }
-
- if ((encoding & 0x07) == 0x00)
- encoding |= DW_EH_PE_udata4;
-
- switch (encoding & DW_EH_PE_FORMAT_MASK) {
- case DW_EH_PE_sdata4:
- *val += dw_read(cur, s32, end);
- break;
- case DW_EH_PE_udata4:
- *val += dw_read(cur, u32, end);
- break;
- case DW_EH_PE_sdata8:
- *val += dw_read(cur, s64, end);
- break;
- case DW_EH_PE_udata8:
- *val += dw_read(cur, u64, end);
- break;
- default:
- return -EINVAL;
- }
-
- out:
- *p = cur;
- return 0;
-}
-
-#define dw_read_encoded_value(ptr, end, enc) ({ \
- u64 __v; \
- if (__dw_read_encoded_value(&ptr, end, &__v, enc)) { \
- return -EINVAL; \
- } \
- __v; \
- })
-
-static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
- GElf_Shdr *shp, const char *name)
-{
- Elf_Scn *sec = NULL;
-
- while ((sec = elf_nextscn(elf, sec)) != NULL) {
- char *str;
-
- gelf_getshdr(sec, shp);
- str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name);
- if (!strcmp(name, str))
- break;
- }
-
- return sec;
-}
-
-static u64 elf_section_offset(int fd, const char *name)
-{
- Elf *elf;
- GElf_Ehdr ehdr;
- GElf_Shdr shdr;
- u64 offset = 0;
-
- elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
- if (elf == NULL)
- return 0;
-
- do {
- if (gelf_getehdr(elf, &ehdr) == NULL)
- break;
-
- if (!elf_section_by_name(elf, &ehdr, &shdr, name))
- break;
-
- offset = shdr.sh_offset;
- } while (0);
-
- elf_end(elf);
- return offset;
-}
-
-struct table_entry {
- u32 start_ip_offset;
- u32 fde_offset;
-};
-
-struct eh_frame_hdr {
- unsigned char version;
- unsigned char eh_frame_ptr_enc;
- unsigned char fde_count_enc;
- unsigned char table_enc;
-
- /*
- * The rest of the header is variable-length and consists of the
- * following members:
- *
- * encoded_t eh_frame_ptr;
- * encoded_t fde_count;
- */
-
- /* A single encoded pointer should not be more than 8 bytes. */
- u64 enc[2];
-
- /*
- * struct {
- * encoded_t start_ip;
- * encoded_t fde_addr;
- * } binary_search_table[fde_count];
- */
- char data[0];
-} __attribute__((__packed__));
-
-int dso_data_fd(vma* dso)
-{
- return open(dso->name.c_str(), O_RDONLY);
-}
-
-ssize_t dso_read(vma *dso, u64 offset, u8 *data, ssize_t size)
-{
- ssize_t ret = -1;
- int fd;
-
- fd = dso_data_fd(dso);
- if (fd < 0)
- return -1;
-
- do {
- if (-1 == lseek(fd, offset, SEEK_SET))
- break;
-
- ret = read(fd, data, size);
- if (ret <= 0)
- break;
- } while (0);
-
- close(fd);
- return ret;
-}
-
-ssize_t dso__data_read_offset(vma *dso, u64 offset, u8 *data, ssize_t size)
-{
- ssize_t r = 0;
- u8 *p = data;
-
- do {
- ssize_t ret;
- ret = dso_read(dso, offset, p, size);
- if (ret <= 0) {
- return -1;
- }
- if (ret > size) {
- return -1;
- }
- r += ret;
- p += ret;
- offset += ret;
- size -= ret;
- } while (size);
- return r;
-}
-
-ssize_t dso__data_read_addr(vma *map,
- u64 addr, u8 *data, ssize_t size)
-{
- u64 offset;
-
- if (map->name.size() > 0 && map->name[0] != '/')
- return 0;
-
- offset = addr - map->start + map->offset;
- return dso__data_read_offset(map, offset, data, size);
-}
-
-
-static int unwind_spec_ehframe(vma *dso,
- u64 offset, u64 *table_data, u64 *segbase,
- u64 *fde_count)
-{
- struct eh_frame_hdr hdr;
- u8 *enc = (u8 *) &hdr.enc;
- u8 *end = (u8 *) &hdr.data;
- ssize_t r;
-
- r = dso__data_read_offset(dso, offset, (u8 *) &hdr, sizeof(hdr));
- if (r != sizeof(hdr)) {
- return -EINVAL;
- }
-
- /* We dont need eh_frame_ptr, just skip it. */
- dw_read_encoded_value(enc, end, hdr.eh_frame_ptr_enc);
-
- *fde_count = dw_read_encoded_value(enc, end, hdr.fde_count_enc);
- *segbase = offset;
- *table_data = (enc - (u8 *) &hdr) + offset;
-
- return 0;
-}
-
-static int read_unwind_spec(vma* dso, u64 *table_data, u64 *segbase, u64 *fde_count)
-{
- int ret = -EINVAL, fd;
-
- if (dso->eh_frame_hdr_offset == 0 && dso->elf_read_error == 0) {
- fd = dso_data_fd(dso);
- if (fd < 0)
- return -EINVAL;
-
- dso->eh_frame_hdr_offset = elf_section_offset(fd, ".eh_frame_hdr");
- close(fd);
- ret = unwind_spec_ehframe(dso, dso->eh_frame_hdr_offset,
- &dso->table_data, &dso->eh_frame_hdr_offset,
- &dso->fde_count);
- if (ret != 0) {
- dso->eh_frame_hdr_offset = 0;
- dso->elf_read_error = 1;
- return -EINVAL;
- }
- }
-
- *table_data = dso->table_data;
- *segbase = dso->eh_frame_hdr_offset;
- *fde_count = dso->fde_count;
-
- /* TODO .debug_frame check if eh_frame_hdr fails */
- return 0;
-}
-
-static vma* find_map(unw_word_t ip, struct unwind_info *ui)
-{
- return ui->sp->find_vma(ui->pid, ip);
-}
-
-static int
-find_proc_info(unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi,
- int need_unwind_info, void *arg)
-{
- struct unwind_info *ui = (struct unwind_info *)arg;
- unw_dyn_info_t di;
- u64 table_data, segbase, fde_count;
-
- vma* map;
- map = find_map(ip, ui);
- if (!map) {
- return -EINVAL;
- }
-
- if (!read_unwind_spec(map, &table_data, &segbase, &fde_count)) {
- memset(&di, 0, sizeof(di));
- di.format = UNW_INFO_FORMAT_REMOTE_TABLE;
- di.start_ip = map->start;
- di.end_ip = map->end;
- di.u.rti.segbase = map->start + segbase;
- di.u.rti.table_data = map->start + table_data;
- di.u.rti.table_len = fde_count * sizeof(struct table_entry)
- / sizeof(unw_word_t);
- return dwarf_search_unwind_table(as, ip, &di, pi,
- need_unwind_info, arg);
- }
- //return -EINVAL;
- return -UNW_ENOINFO;
-}
-
-static int access_fpreg(unw_addr_space_t as,
- unw_regnum_t num,
- unw_fpreg_t *val,
- int __write,
- void *arg)
-{
- return -UNW_EINVAL;
-}
-
-static int get_dyn_info_list_addr(unw_addr_space_t as,
- unw_word_t *dil_addr,
- void *arg)
-{
- return -UNW_ENOINFO;
-}
-
-static int resume(unw_addr_space_t as,
- unw_cursor_t *cu,
- void *arg)
-{
- return -UNW_EINVAL;
-}
-
-static int
-get_proc_name(unw_addr_space_t as,
- unw_word_t addr,
- char *bufp, size_t buf_len,
- unw_word_t *offp, void *arg)
-{
- return -UNW_EINVAL;
-}
-
-struct map *last_map = NULL;
-static int access_dso_mem(struct unwind_info *ui, unw_word_t addr,
- unw_word_t *data)
-{
- ssize_t size;
-
- // ip in the first page is invalid
- if ( addr == 0 || addr == (unsigned long)(-1) || (long)addr < 4096 ) {
- return -UNW_ENOINFO;
- }
-
- vma *map;
- map = find_map(addr, ui);
- if (!map) {
- return -UNW_ENOINFO;
- }
-
- if (map->type != NATIVE_TYPE) {
- return -UNW_ENOINFO;
- }
-
- size = dso__data_read_addr(map,
- addr, (u8 *) data, sizeof(*data));
-
- return !(size == sizeof(*data));
-}
-
-/*
- * Optimization point.
- */
-static int reg_value(unw_word_t *valp, struct regs_dump *regs, int id)
-{
- /* we only support 3 registers. RIP, RSP and RBP */
- if (id < 0 || id > 2)
- return -EINVAL;
-
- *valp = regs->regs[id];
- return 0;
-}
-
-unw_word_t last_addr = 0;
-unw_word_t last_val = 0;
-int stack_offset = 0;
-
-static int access_mem(unw_addr_space_t as,
- unw_word_t addr, unw_word_t *valp,
- int __write, void *arg)
-{
- struct unwind_info *ui = (struct unwind_info *)arg;
- struct stack_dump *stack = &ui->sample->user_stack;
- unw_word_t start, end;
- int offset;
- int ret;
-
- if (addr == last_addr) {
- (*valp) = last_val;
- return 0;
- }
-
- last_addr = addr;
-
- /* Don't support write, probably not needed. */
- if (__write || !stack || !ui->sample->user_regs.regs) {
- *valp = 0;
- // fprintf(stderr, "access_mem: __write memory\n");
- last_val = *valp;
- return 0;
- }
-
- /* start is the SP */
- ret = reg_value(&start, &ui->sample->user_regs, PERF_REG_SP);
- if (ret) {
- // fprintf(stderr, "access_mem: reg_value error (ret: %d)\n", ret);
- return ret;
- }
-
- end = start + stack->size;
-
- /* Check overflow. */
- if (addr + sizeof(unw_word_t) < addr) {
- // fprintf(stderr, "access_mem: Check overflow.\n");
- return -EINVAL;
- }
-
- if (addr < start || addr + sizeof(unw_word_t) >= end) {
- ret = access_dso_mem(ui, addr, valp);
- if (ret) {
- // pr_debug("unwind: access_mem %p not inside range %p-%p\n",
- // (void *)addr, (void *)start, (void *)end);
- *valp = 0;
- last_val = 0;
- return ret;
- }
- last_val = *valp;
- return 0;
- }
-
- offset = addr - start;
- *valp = *(unw_word_t *)&stack->data[offset];
- last_val = *valp;
- stack_offset = offset;
-
- //pr_debug("unwind: access_mem addr %p, val %lx, offset %d\n",
- // (void *)addr, (unsigned long)*valp, offset);
- return 0;
-}
-
-static int access_reg(unw_addr_space_t as,
- unw_regnum_t regnum, unw_word_t *valp,
- int __write, void *arg)
-{
- struct unwind_info *ui = (struct unwind_info *)arg;
- int id, ret;
-
- /* Don't support write, I suspect we don't need it. */
- if (__write) {
- //pr_err("unwind: access_reg w %d\n", regnum);
- return 0;
- }
-
- if (!ui->sample->user_regs.regs) {
- *valp = 0;
- return 0;
- }
-
- id = unwind__arch_reg_id(regnum);
- if (id < 0) {
- //fprintf(stderr, "Cannot get reg: %d\n", regnum);
- return -EINVAL;
- }
-
- ret = reg_value(valp, &ui->sample->user_regs, id);
- if (ret) {
- //pr_err("unwind: can't read reg %d\n", regnum);
- return ret;
- }
-
- //pr_debug("unwind: reg %d, val %lx\n", regnum, (unsigned long)*valp);
- return 0;
-}
-
-static void put_unwind_info(unw_addr_space_t as,
- unw_proc_info_t *pi,
- void *arg)
-{
- //pr_debug("unwind: put_unwind_info called\n");
-}
-
-static int entry(u64 ip, int pid, int pid_ns, unwind_entry_cb_t cb, void *arg)
-{
- struct unwind_entry e;
-
- e.ip = ip;
- e.pid = pid;
- e.pid_ns = pid_ns;
-
- return cb(&e, arg);
-}
-
-static unw_accessors_t accessors = {
- .find_proc_info = find_proc_info,
- .put_unwind_info = put_unwind_info,
- .get_dyn_info_list_addr = get_dyn_info_list_addr,
- .access_mem = access_mem,
- .access_reg = access_reg,
- .access_fpreg = access_fpreg,
- .resume = resume,
- .get_proc_name = get_proc_name,
-};
-
-static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb,
- void *arg)
-{
- unw_addr_space_t addr_space;
- unw_cursor_t c;
- entry_cb_arg_t *cb_arg = (entry_cb_arg_t *)arg;
- int ret;
- int loops = 0;
-
- addr_space = unw_create_addr_space(&accessors, 0);
- if (!addr_space) {
- //pr_err("unwind: Can't create unwind address space.\n");
- return -ENOMEM;
- }
-
- unw_set_caching_policy(addr_space, UNW_CACHE_GLOBAL);
-
- ret = unw_init_remote(&c, addr_space, ui); /* @ui is args */
-
- while (!ret && (unw_step(&c) > 0)) {
- unw_word_t ip;
-
- unw_get_reg(&c, UNW_REG_IP, &ip); //get IP from current step;
- cb_arg->arg = &c;
- ret = entry(ip, ui->pid, ui->pid_ns, cb, cb_arg);
-
- loops++;
- if (loops >= 50)
- break;
- }
-
- unw_destroy_addr_space(addr_space);
- return ret;
-}
-
-int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
- symbol_parser *sp, int pid, int pid_ns,
- struct perf_sample *data)
-{
- unw_word_t ip;
- struct unwind_info ui = {
- .sample = data,
- .pid = pid,
- .pid_ns = pid_ns,
- .sp = sp,
- };
- int ret;
-
- if (!data->user_regs.regs)
- return -EINVAL;
-
- ret = reg_value(&ip, &data->user_regs, PERF_REG_IP);
- if (ret)
- return ret;
-
- ret = entry(ip, pid, pid_ns, cb, arg);
- if (ret)
- return -ENOMEM;
-
- return get_entries(&ui, cb, arg);
-}
diff --git a/source/ucli_py/unwind/unwind.h b/source/ucli_py/unwind/unwind.h
deleted file mode 100644
index a18cea2..0000000
--- a/source/ucli_py/unwind/unwind.h
+++ /dev/null
@@ -1,101 +0,0 @@
-#ifndef __UNWIND_H
-#define __UNWIND_H
-
-#include <libunwind.h>
-#include "symbol.h"
-
-typedef unsigned long u64;
-typedef unsigned char u8;
-typedef unsigned int u32;
-typedef long s64;
-typedef char s8;
-typedef int s32;
-
-
-struct regs_dump {
- u64 *regs;
-};
-
-struct ip_callchain {
- u64 nr;
- u64 ips[0];
-};
-
-struct branch_flags {
- u64 mispred:1;
- u64 predicted:1;
- u64 reserved:62;
-};
-
-struct branch_entry {
- u64 from;
- u64 to;
- struct branch_flags flags;
-};
-
-struct branch_stack {
- u64 nr;
- struct branch_entry entries[0];
-};
-
-struct stack_dump {
- unsigned short offset;
- u64 size;
- char *data;
-};
-
-struct perf_sample {
- u64 ip;
- u32 pid, tid;
- u64 time;
- u64 addr;
- u64 id;
- u64 stream_id;
- u64 period;
- u32 cpu;
- u32 raw_size;
- void *raw_data;
- struct ip_callchain *callchain;
- struct branch_stack *branch_stack;
- struct regs_dump user_regs;
- struct stack_dump user_stack;
-};
-
-#define PERF_REG_IP 0
-#define PERF_REG_SP 1
-#define PERF_REG_BP 2
-
-struct unwind_entry {
- int pid;
- int pid_ns;
- u64 ip;
- struct vma *map;
-};
-
-typedef struct {
- struct perf_sample *stack_sample;
- void *arg;
-} entry_cb_arg_t;
-
-typedef int (*unwind_entry_cb_t)(struct unwind_entry *entry, void *arg);
-
-int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
- symbol_parser *sp,
- int pid, int pid_ns,
- struct perf_sample *data);
-int unwind__arch_reg_id(int regnum);
-
-extern int stack_offset;
-static inline void clear_stack_offset(void)
-{
- stack_offset = 0;
-}
-
-static inline int get_stack_offset(void)
-{
- return stack_offset;
-}
-
-extern void unwind__get_rbp(void *arg);
-
-#endif /* __UNWIND_H */