summaryrefslogtreecommitdiff
path: root/source/ucli/unwind.cc
blob: bc57c1583877e242e30dbab94add88152bb4a3d1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#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) {
//   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("##C++ pid %d\n", pid);

//   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);
//   fflush(stdout);
// }