~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/perf/util/unwind-libdw.c

Version: ~ [ linux-6.12-rc7 ] ~ [ linux-6.11.7 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.60 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.116 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.171 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.229 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.285 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.323 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.12 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

Diff markup

Differences between /tools/perf/util/unwind-libdw.c (Architecture mips) and /tools/perf/util/unwind-libdw.c (Architecture ppc)


  1 // SPDX-License-Identifier: GPL-2.0                 1 // SPDX-License-Identifier: GPL-2.0
  2 #include <linux/compiler.h>                         2 #include <linux/compiler.h>
  3 #include <elfutils/libdw.h>                         3 #include <elfutils/libdw.h>
  4 #include <elfutils/libdwfl.h>                       4 #include <elfutils/libdwfl.h>
  5 #include <inttypes.h>                               5 #include <inttypes.h>
  6 #include <errno.h>                                  6 #include <errno.h>
  7 #include "debug.h"                                  7 #include "debug.h"
  8 #include "dso.h"                                    8 #include "dso.h"
  9 #include "unwind.h"                                 9 #include "unwind.h"
 10 #include "unwind-libdw.h"                          10 #include "unwind-libdw.h"
 11 #include "machine.h"                               11 #include "machine.h"
 12 #include "map.h"                                   12 #include "map.h"
 13 #include "symbol.h"                                13 #include "symbol.h"
 14 #include "thread.h"                                14 #include "thread.h"
 15 #include <linux/types.h>                           15 #include <linux/types.h>
 16 #include <linux/zalloc.h>                          16 #include <linux/zalloc.h>
 17 #include "event.h"                                 17 #include "event.h"
 18 #include "perf_regs.h"                             18 #include "perf_regs.h"
 19 #include "callchain.h"                             19 #include "callchain.h"
 20 #include "util/env.h"                              20 #include "util/env.h"
 21                                                    21 
 22 static char *debuginfo_path;                       22 static char *debuginfo_path;
 23                                                    23 
 24 static int __find_debuginfo(Dwfl_Module *mod _     24 static int __find_debuginfo(Dwfl_Module *mod __maybe_unused, void **userdata,
 25                             const char *modnam     25                             const char *modname __maybe_unused, Dwarf_Addr base __maybe_unused,
 26                             const char *file_n     26                             const char *file_name, const char *debuglink_file __maybe_unused,
 27                             GElf_Word debuglin     27                             GElf_Word debuglink_crc __maybe_unused, char **debuginfo_file_name)
 28 {                                                  28 {
 29         const struct dso *dso = *userdata;         29         const struct dso *dso = *userdata;
 30                                                    30 
 31         assert(dso);                               31         assert(dso);
 32         if (dso__symsrc_filename(dso) && strcm     32         if (dso__symsrc_filename(dso) && strcmp(file_name, dso__symsrc_filename(dso)))
 33                 *debuginfo_file_name = strdup(     33                 *debuginfo_file_name = strdup(dso__symsrc_filename(dso));
 34         return -1;                                 34         return -1;
 35 }                                                  35 }
 36                                                    36 
 37 static const Dwfl_Callbacks offline_callbacks      37 static const Dwfl_Callbacks offline_callbacks = {
 38         .find_debuginfo         = __find_debug     38         .find_debuginfo         = __find_debuginfo,
 39         .debuginfo_path         = &debuginfo_p     39         .debuginfo_path         = &debuginfo_path,
 40         .section_address        = dwfl_offline     40         .section_address        = dwfl_offline_section_address,
 41         // .find_elf is not set as we use dwfl     41         // .find_elf is not set as we use dwfl_report_elf() instead.
 42 };                                                 42 };
 43                                                    43 
 44 static int __report_module(struct addr_locatio     44 static int __report_module(struct addr_location *al, u64 ip,
 45                             struct unwind_info     45                             struct unwind_info *ui)
 46 {                                                  46 {
 47         Dwfl_Module *mod;                          47         Dwfl_Module *mod;
 48         struct dso *dso = NULL;                    48         struct dso *dso = NULL;
 49         Dwarf_Addr base;                           49         Dwarf_Addr base;
 50         /*                                         50         /*
 51          * Some callers will use al->sym, so w     51          * Some callers will use al->sym, so we can't just use the
 52          * cheaper thread__find_map() here.        52          * cheaper thread__find_map() here.
 53          */                                        53          */
 54         thread__find_symbol(ui->thread, PERF_R     54         thread__find_symbol(ui->thread, PERF_RECORD_MISC_USER, ip, al);
 55                                                    55 
 56         if (al->map)                               56         if (al->map)
 57                 dso = map__dso(al->map);           57                 dso = map__dso(al->map);
 58                                                    58 
 59         if (!dso)                                  59         if (!dso)
 60                 return 0;                          60                 return 0;
 61                                                    61 
 62         /*                                         62         /*
 63          * The generated JIT DSO files only ma     63          * The generated JIT DSO files only map the code segment without
 64          * ELF headers.  Since JIT codes used      64          * ELF headers.  Since JIT codes used to be packed in a memory
 65          * segment, calculating the base addre     65          * segment, calculating the base address using pgoff falls into
 66          * a different code in another DSO.  S     66          * a different code in another DSO.  So just use the map->start
 67          * directly to pick the correct one.       67          * directly to pick the correct one.
 68          */                                        68          */
 69         if (!strncmp(dso__long_name(dso), "/tm     69         if (!strncmp(dso__long_name(dso), "/tmp/jitted-", 12))
 70                 base = map__start(al->map);        70                 base = map__start(al->map);
 71         else                                       71         else
 72                 base = map__start(al->map) - m     72                 base = map__start(al->map) - map__pgoff(al->map);
 73                                                    73 
 74         mod = dwfl_addrmodule(ui->dwfl, ip);       74         mod = dwfl_addrmodule(ui->dwfl, ip);
 75         if (mod) {                                 75         if (mod) {
 76                 Dwarf_Addr s;                      76                 Dwarf_Addr s;
 77                                                    77 
 78                 dwfl_module_info(mod, NULL, &s     78                 dwfl_module_info(mod, NULL, &s, NULL, NULL, NULL, NULL, NULL);
 79                 if (s != base)                     79                 if (s != base)
 80                         mod = NULL;                80                         mod = NULL;
 81         }                                          81         }
 82                                                    82 
 83         if (!mod) {                                83         if (!mod) {
 84                 char filename[PATH_MAX];           84                 char filename[PATH_MAX];
 85                                                    85 
 86                 __symbol__join_symfs(filename,     86                 __symbol__join_symfs(filename, sizeof(filename), dso__long_name(dso));
 87                 mod = dwfl_report_elf(ui->dwfl     87                 mod = dwfl_report_elf(ui->dwfl, dso__short_name(dso), filename, -1,
 88                                       base, fa     88                                       base, false);
 89         }                                          89         }
 90         if (!mod) {                                90         if (!mod) {
 91                 char filename[PATH_MAX];           91                 char filename[PATH_MAX];
 92                                                    92 
 93                 if (dso__build_id_filename(dso     93                 if (dso__build_id_filename(dso, filename, sizeof(filename), false))
 94                         mod = dwfl_report_elf(     94                         mod = dwfl_report_elf(ui->dwfl, dso__short_name(dso), filename, -1,
 95                                                    95                                               base, false);
 96         }                                          96         }
 97                                                    97 
 98         if (mod) {                                 98         if (mod) {
 99                 void **userdatap;                  99                 void **userdatap;
100                                                   100 
101                 dwfl_module_info(mod, &userdat    101                 dwfl_module_info(mod, &userdatap, NULL, NULL, NULL, NULL, NULL, NULL);
102                 *userdatap = dso;                 102                 *userdatap = dso;
103         }                                         103         }
104                                                   104 
105         return mod && dwfl_addrmodule(ui->dwfl    105         return mod && dwfl_addrmodule(ui->dwfl, ip) == mod ? 0 : -1;
106 }                                                 106 }
107                                                   107 
108 static int report_module(u64 ip, struct unwind    108 static int report_module(u64 ip, struct unwind_info *ui)
109 {                                                 109 {
110         struct addr_location al;                  110         struct addr_location al;
111         int res;                                  111         int res;
112                                                   112 
113         addr_location__init(&al);                 113         addr_location__init(&al);
114         res = __report_module(&al, ip, ui);       114         res = __report_module(&al, ip, ui);
115         addr_location__exit(&al);                 115         addr_location__exit(&al);
116         return res;                               116         return res;
117 }                                                 117 }
118                                                   118 
119 /*                                                119 /*
120  * Store all entries within entries array,        120  * Store all entries within entries array,
121  * we will process it after we finish unwind.     121  * we will process it after we finish unwind.
122  */                                               122  */
123 static int entry(u64 ip, struct unwind_info *u    123 static int entry(u64 ip, struct unwind_info *ui)
124                                                   124 
125 {                                                 125 {
126         struct unwind_entry *e = &ui->entries[    126         struct unwind_entry *e = &ui->entries[ui->idx++];
127         struct addr_location al;                  127         struct addr_location al;
128                                                   128 
129         addr_location__init(&al);                 129         addr_location__init(&al);
130         if (__report_module(&al, ip, ui)) {       130         if (__report_module(&al, ip, ui)) {
131                 addr_location__exit(&al);         131                 addr_location__exit(&al);
132                 return -1;                        132                 return -1;
133         }                                         133         }
134                                                   134 
135         e->ip     = ip;                           135         e->ip     = ip;
136         e->ms.maps = al.maps;                     136         e->ms.maps = al.maps;
137         e->ms.map = al.map;                       137         e->ms.map = al.map;
138         e->ms.sym = al.sym;                       138         e->ms.sym = al.sym;
139                                                   139 
140         pr_debug("unwind: %s:ip = 0x%" PRIx64     140         pr_debug("unwind: %s:ip = 0x%" PRIx64 " (0x%" PRIx64 ")\n",
141                  al.sym ? al.sym->name : "''",    141                  al.sym ? al.sym->name : "''",
142                  ip,                              142                  ip,
143                  al.map ? map__map_ip(al.map,     143                  al.map ? map__map_ip(al.map, ip) : (u64) 0);
144         addr_location__exit(&al);                 144         addr_location__exit(&al);
145         return 0;                                 145         return 0;
146 }                                                 146 }
147                                                   147 
148 static pid_t next_thread(Dwfl *dwfl, void *arg    148 static pid_t next_thread(Dwfl *dwfl, void *arg, void **thread_argp)
149 {                                                 149 {
150         /* We want only single thread to be pr    150         /* We want only single thread to be processed. */
151         if (*thread_argp != NULL)                 151         if (*thread_argp != NULL)
152                 return 0;                         152                 return 0;
153                                                   153 
154         *thread_argp = arg;                       154         *thread_argp = arg;
155         return dwfl_pid(dwfl);                    155         return dwfl_pid(dwfl);
156 }                                                 156 }
157                                                   157 
158 static int access_dso_mem(struct unwind_info *    158 static int access_dso_mem(struct unwind_info *ui, Dwarf_Addr addr,
159                           Dwarf_Word *data)       159                           Dwarf_Word *data)
160 {                                                 160 {
161         struct addr_location al;                  161         struct addr_location al;
162         ssize_t size;                             162         ssize_t size;
163         struct dso *dso;                          163         struct dso *dso;
164                                                   164 
165         addr_location__init(&al);                 165         addr_location__init(&al);
166         if (!thread__find_map(ui->thread, PERF    166         if (!thread__find_map(ui->thread, PERF_RECORD_MISC_USER, addr, &al)) {
167                 pr_debug("unwind: no map for %    167                 pr_debug("unwind: no map for %lx\n", (unsigned long)addr);
168                 goto out_fail;                    168                 goto out_fail;
169         }                                         169         }
170         dso = map__dso(al.map);                   170         dso = map__dso(al.map);
171         if (!dso)                                 171         if (!dso)
172                 goto out_fail;                    172                 goto out_fail;
173                                                   173 
174         size = dso__data_read_addr(dso, al.map    174         size = dso__data_read_addr(dso, al.map, ui->machine, addr, (u8 *) data, sizeof(*data));
175                                                   175 
176         addr_location__exit(&al);                 176         addr_location__exit(&al);
177         return !(size == sizeof(*data));          177         return !(size == sizeof(*data));
178 out_fail:                                         178 out_fail:
179         addr_location__exit(&al);                 179         addr_location__exit(&al);
180         return -1;                                180         return -1;
181 }                                                 181 }
182                                                   182 
183 static bool memory_read(Dwfl *dwfl __maybe_unu    183 static bool memory_read(Dwfl *dwfl __maybe_unused, Dwarf_Addr addr, Dwarf_Word *result,
184                         void *arg)                184                         void *arg)
185 {                                                 185 {
186         struct unwind_info *ui = arg;             186         struct unwind_info *ui = arg;
187         const char *arch = perf_env__arch(ui->    187         const char *arch = perf_env__arch(ui->machine->env);
188         struct stack_dump *stack = &ui->sample    188         struct stack_dump *stack = &ui->sample->user_stack;
189         u64 start, end;                           189         u64 start, end;
190         int offset;                               190         int offset;
191         int ret;                                  191         int ret;
192                                                   192 
193         ret = perf_reg_value(&start, &ui->samp    193         ret = perf_reg_value(&start, &ui->sample->user_regs,
194                              perf_arch_reg_sp(    194                              perf_arch_reg_sp(arch));
195         if (ret)                                  195         if (ret)
196                 return false;                     196                 return false;
197                                                   197 
198         end = start + stack->size;                198         end = start + stack->size;
199                                                   199 
200         /* Check overflow. */                     200         /* Check overflow. */
201         if (addr + sizeof(Dwarf_Word) < addr)     201         if (addr + sizeof(Dwarf_Word) < addr)
202                 return false;                     202                 return false;
203                                                   203 
204         if (addr < start || addr + sizeof(Dwar    204         if (addr < start || addr + sizeof(Dwarf_Word) > end) {
205                 ret = access_dso_mem(ui, addr,    205                 ret = access_dso_mem(ui, addr, result);
206                 if (ret) {                        206                 if (ret) {
207                         pr_debug("unwind: acce    207                         pr_debug("unwind: access_mem 0x%" PRIx64 " not inside range"
208                                  " 0x%" PRIx64    208                                  " 0x%" PRIx64 "-0x%" PRIx64 "\n",
209                                 addr, start, e    209                                 addr, start, end);
210                         return false;             210                         return false;
211                 }                                 211                 }
212                 return true;                      212                 return true;
213         }                                         213         }
214                                                   214 
215         offset  = addr - start;                   215         offset  = addr - start;
216         *result = *(Dwarf_Word *)&stack->data[    216         *result = *(Dwarf_Word *)&stack->data[offset];
217         pr_debug("unwind: access_mem addr 0x%"    217         pr_debug("unwind: access_mem addr 0x%" PRIx64 ", val %lx, offset %d\n",
218                  addr, (unsigned long)*result,    218                  addr, (unsigned long)*result, offset);
219         return true;                              219         return true;
220 }                                                 220 }
221                                                   221 
222 static const Dwfl_Thread_Callbacks callbacks =    222 static const Dwfl_Thread_Callbacks callbacks = {
223         .next_thread            = next_thread,    223         .next_thread            = next_thread,
224         .memory_read            = memory_read,    224         .memory_read            = memory_read,
225         .set_initial_registers  = libdw__arch_    225         .set_initial_registers  = libdw__arch_set_initial_registers,
226 };                                                226 };
227                                                   227 
228 static int                                        228 static int
229 frame_callback(Dwfl_Frame *state, void *arg)      229 frame_callback(Dwfl_Frame *state, void *arg)
230 {                                                 230 {
231         struct unwind_info *ui = arg;             231         struct unwind_info *ui = arg;
232         Dwarf_Addr pc;                            232         Dwarf_Addr pc;
233         bool isactivation;                        233         bool isactivation;
234                                                   234 
235         if (!dwfl_frame_pc(state, &pc, NULL))     235         if (!dwfl_frame_pc(state, &pc, NULL)) {
236                 if (!ui->best_effort)             236                 if (!ui->best_effort)
237                         pr_err("%s", dwfl_errm    237                         pr_err("%s", dwfl_errmsg(-1));
238                 return DWARF_CB_ABORT;            238                 return DWARF_CB_ABORT;
239         }                                         239         }
240                                                   240 
241         // report the module before we query f    241         // report the module before we query for isactivation
242         report_module(pc, ui);                    242         report_module(pc, ui);
243                                                   243 
244         if (!dwfl_frame_pc(state, &pc, &isacti    244         if (!dwfl_frame_pc(state, &pc, &isactivation)) {
245                 if (!ui->best_effort)             245                 if (!ui->best_effort)
246                         pr_err("%s", dwfl_errm    246                         pr_err("%s", dwfl_errmsg(-1));
247                 return DWARF_CB_ABORT;            247                 return DWARF_CB_ABORT;
248         }                                         248         }
249                                                   249 
250         if (!isactivation)                        250         if (!isactivation)
251                 --pc;                             251                 --pc;
252                                                   252 
253         return entry(pc, ui) || !(--ui->max_st    253         return entry(pc, ui) || !(--ui->max_stack) ?
254                DWARF_CB_ABORT : DWARF_CB_OK;      254                DWARF_CB_ABORT : DWARF_CB_OK;
255 }                                                 255 }
256                                                   256 
257 int unwind__get_entries(unwind_entry_cb_t cb,     257 int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
258                         struct thread *thread,    258                         struct thread *thread,
259                         struct perf_sample *da    259                         struct perf_sample *data,
260                         int max_stack,            260                         int max_stack,
261                         bool best_effort)         261                         bool best_effort)
262 {                                                 262 {
263         struct unwind_info *ui, ui_buf = {        263         struct unwind_info *ui, ui_buf = {
264                 .sample         = data,           264                 .sample         = data,
265                 .thread         = thread,         265                 .thread         = thread,
266                 .machine        = maps__machin    266                 .machine        = maps__machine((thread__maps(thread))),
267                 .cb             = cb,             267                 .cb             = cb,
268                 .arg            = arg,            268                 .arg            = arg,
269                 .max_stack      = max_stack,      269                 .max_stack      = max_stack,
270                 .best_effort    = best_effort     270                 .best_effort    = best_effort
271         };                                        271         };
272         const char *arch = perf_env__arch(ui_b    272         const char *arch = perf_env__arch(ui_buf.machine->env);
273         Dwarf_Word ip;                            273         Dwarf_Word ip;
274         int err = -EINVAL, i;                     274         int err = -EINVAL, i;
275                                                   275 
276         if (!data->user_regs.regs)                276         if (!data->user_regs.regs)
277                 return -EINVAL;                   277                 return -EINVAL;
278                                                   278 
279         ui = zalloc(sizeof(ui_buf) + sizeof(ui    279         ui = zalloc(sizeof(ui_buf) + sizeof(ui_buf.entries[0]) * max_stack);
280         if (!ui)                                  280         if (!ui)
281                 return -ENOMEM;                   281                 return -ENOMEM;
282                                                   282 
283         *ui = ui_buf;                             283         *ui = ui_buf;
284                                                   284 
285         ui->dwfl = dwfl_begin(&offline_callbac    285         ui->dwfl = dwfl_begin(&offline_callbacks);
286         if (!ui->dwfl)                            286         if (!ui->dwfl)
287                 goto out;                         287                 goto out;
288                                                   288 
289         err = perf_reg_value(&ip, &data->user_    289         err = perf_reg_value(&ip, &data->user_regs, perf_arch_reg_ip(arch));
290         if (err)                                  290         if (err)
291                 goto out;                         291                 goto out;
292                                                   292 
293         err = report_module(ip, ui);              293         err = report_module(ip, ui);
294         if (err)                                  294         if (err)
295                 goto out;                         295                 goto out;
296                                                   296 
297         err = !dwfl_attach_state(ui->dwfl, EM_    297         err = !dwfl_attach_state(ui->dwfl, EM_NONE, thread__tid(thread), &callbacks, ui);
298         if (err)                                  298         if (err)
299                 goto out;                         299                 goto out;
300                                                   300 
301         err = dwfl_getthread_frames(ui->dwfl,     301         err = dwfl_getthread_frames(ui->dwfl, thread__tid(thread), frame_callback, ui);
302                                                   302 
303         if (err && ui->max_stack != max_stack)    303         if (err && ui->max_stack != max_stack)
304                 err = 0;                          304                 err = 0;
305                                                   305 
306         /*                                        306         /*
307          * Display what we got based on the or    307          * Display what we got based on the order setup.
308          */                                       308          */
309         for (i = 0; i < ui->idx && !err; i++)     309         for (i = 0; i < ui->idx && !err; i++) {
310                 int j = i;                        310                 int j = i;
311                                                   311 
312                 if (callchain_param.order == O    312                 if (callchain_param.order == ORDER_CALLER)
313                         j = ui->idx - i - 1;      313                         j = ui->idx - i - 1;
314                                                   314 
315                 err = ui->entries[j].ip ? ui->    315                 err = ui->entries[j].ip ? ui->cb(&ui->entries[j], ui->arg) : 0;
316         }                                         316         }
317                                                   317 
318  out:                                             318  out:
319         if (err)                                  319         if (err)
320                 pr_debug("unwind: failed with     320                 pr_debug("unwind: failed with '%s'\n", dwfl_errmsg(-1));
321                                                   321 
322         dwfl_end(ui->dwfl);                       322         dwfl_end(ui->dwfl);
323         free(ui);                                 323         free(ui);
324         return 0;                                 324         return 0;
325 }                                                 325 }
326                                                   326 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php