aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf')
-rw-r--r--tools/perf/Documentation/perf-script.txt4
-rw-r--r--tools/perf/builtin-script.c2
-rw-r--r--tools/perf/ui/hist.c2
-rw-r--r--tools/perf/util/callchain.c13
-rw-r--r--tools/perf/util/evsel_fprintf.c33
-rw-r--r--tools/perf/util/srcline.c49
-rw-r--r--tools/perf/util/unwind-libdw.c6
-rw-r--r--tools/perf/util/unwind-libunwind-local.c11
8 files changed, 92 insertions, 28 deletions
diff --git a/tools/perf/Documentation/perf-script.txt b/tools/perf/Documentation/perf-script.txt
index cb0eda3925e6..3517e204a2b3 100644
--- a/tools/perf/Documentation/perf-script.txt
+++ b/tools/perf/Documentation/perf-script.txt
@@ -311,6 +311,10 @@ include::itrace.txt[]
311 Set the maximum number of program blocks to print with brstackasm for 311 Set the maximum number of program blocks to print with brstackasm for
312 each sample. 312 each sample.
313 313
314--inline::
315 If a callgraph address belongs to an inlined function, the inline stack
316 will be printed. Each entry has function name and file/line.
317
314SEE ALSO 318SEE ALSO
315-------- 319--------
316linkperf:perf-record[1], linkperf:perf-script-perl[1], 320linkperf:perf-record[1], linkperf:perf-script-perl[1],
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index d05aec491cff..4761b0d7fcb5 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -2494,6 +2494,8 @@ int cmd_script(int argc, const char **argv)
2494 "Enable kernel symbol demangling"), 2494 "Enable kernel symbol demangling"),
2495 OPT_STRING(0, "time", &script.time_str, "str", 2495 OPT_STRING(0, "time", &script.time_str, "str",
2496 "Time span of interest (start,stop)"), 2496 "Time span of interest (start,stop)"),
2497 OPT_BOOLEAN(0, "inline", &symbol_conf.inline_name,
2498 "Show inline function"),
2497 OPT_END() 2499 OPT_END()
2498 }; 2500 };
2499 const char * const script_subcommands[] = { "record", "report", NULL }; 2501 const char * const script_subcommands[] = { "record", "report", NULL };
diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c
index 59addd52d9cd..ddb2c6fbdf91 100644
--- a/tools/perf/ui/hist.c
+++ b/tools/perf/ui/hist.c
@@ -210,6 +210,8 @@ static int __hpp__sort_acc(struct hist_entry *a, struct hist_entry *b,
210 return 0; 210 return 0;
211 211
212 ret = b->callchain->max_depth - a->callchain->max_depth; 212 ret = b->callchain->max_depth - a->callchain->max_depth;
213 if (callchain_param.order == ORDER_CALLER)
214 ret = -ret;
213 } 215 }
214 return ret; 216 return ret;
215} 217}
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
index 81fc29ac798f..b4204b43ed58 100644
--- a/tools/perf/util/callchain.c
+++ b/tools/perf/util/callchain.c
@@ -621,14 +621,19 @@ enum match_result {
621static enum match_result match_chain_srcline(struct callchain_cursor_node *node, 621static enum match_result match_chain_srcline(struct callchain_cursor_node *node,
622 struct callchain_list *cnode) 622 struct callchain_list *cnode)
623{ 623{
624 char *left = get_srcline(cnode->ms.map->dso, 624 char *left = NULL;
625 char *right = NULL;
626 enum match_result ret = MATCH_EQ;
627 int cmp;
628
629 if (cnode->ms.map)
630 left = get_srcline(cnode->ms.map->dso,
625 map__rip_2objdump(cnode->ms.map, cnode->ip), 631 map__rip_2objdump(cnode->ms.map, cnode->ip),
626 cnode->ms.sym, true, false); 632 cnode->ms.sym, true, false);
627 char *right = get_srcline(node->map->dso, 633 if (node->map)
634 right = get_srcline(node->map->dso,
628 map__rip_2objdump(node->map, node->ip), 635 map__rip_2objdump(node->map, node->ip),
629 node->sym, true, false); 636 node->sym, true, false);
630 enum match_result ret = MATCH_EQ;
631 int cmp;
632 637
633 if (left && right) 638 if (left && right)
634 cmp = strcmp(left, right); 639 cmp = strcmp(left, right);
diff --git a/tools/perf/util/evsel_fprintf.c b/tools/perf/util/evsel_fprintf.c
index e415aee6a245..583f3a602506 100644
--- a/tools/perf/util/evsel_fprintf.c
+++ b/tools/perf/util/evsel_fprintf.c
@@ -7,6 +7,7 @@
7#include "map.h" 7#include "map.h"
8#include "strlist.h" 8#include "strlist.h"
9#include "symbol.h" 9#include "symbol.h"
10#include "srcline.h"
10 11
11static int comma_fprintf(FILE *fp, bool *first, const char *fmt, ...) 12static int comma_fprintf(FILE *fp, bool *first, const char *fmt, ...)
12{ 13{
@@ -168,6 +169,38 @@ int sample__fprintf_callchain(struct perf_sample *sample, int left_alignment,
168 if (!print_oneline) 169 if (!print_oneline)
169 printed += fprintf(fp, "\n"); 170 printed += fprintf(fp, "\n");
170 171
172 if (symbol_conf.inline_name && node->map) {
173 struct inline_node *inode;
174
175 addr = map__rip_2objdump(node->map, node->ip),
176 inode = dso__parse_addr_inlines(node->map->dso, addr);
177
178 if (inode) {
179 struct inline_list *ilist;
180
181 list_for_each_entry(ilist, &inode->val, list) {
182 if (print_arrow)
183 printed += fprintf(fp, " <-");
184
185 /* IP is same, just skip it */
186 if (print_ip)
187 printed += fprintf(fp, "%c%16s",
188 s, "");
189 if (print_sym)
190 printed += fprintf(fp, " %s",
191 ilist->funcname);
192 if (print_srcline)
193 printed += fprintf(fp, "\n %s:%d",
194 ilist->filename,
195 ilist->line_nr);
196 if (!print_oneline)
197 printed += fprintf(fp, "\n");
198 }
199
200 inline_node__delete(inode);
201 }
202 }
203
171 if (symbol_conf.bt_stop_list && 204 if (symbol_conf.bt_stop_list &&
172 node->sym && 205 node->sym &&
173 strlist__has_entry(symbol_conf.bt_stop_list, 206 strlist__has_entry(symbol_conf.bt_stop_list,
diff --git a/tools/perf/util/srcline.c b/tools/perf/util/srcline.c
index df051a52393c..ebc88a74e67b 100644
--- a/tools/perf/util/srcline.c
+++ b/tools/perf/util/srcline.c
@@ -56,7 +56,10 @@ static int inline_list__append(char *filename, char *funcname, int line_nr,
56 } 56 }
57 } 57 }
58 58
59 list_add_tail(&ilist->list, &node->val); 59 if (callchain_param.order == ORDER_CALLEE)
60 list_add_tail(&ilist->list, &node->val);
61 else
62 list_add(&ilist->list, &node->val);
60 63
61 return 0; 64 return 0;
62} 65}
@@ -200,12 +203,14 @@ static void addr2line_cleanup(struct a2l_data *a2l)
200 203
201#define MAX_INLINE_NEST 1024 204#define MAX_INLINE_NEST 1024
202 205
203static void inline_list__reverse(struct inline_node *node) 206static int inline_list__append_dso_a2l(struct dso *dso,
207 struct inline_node *node)
204{ 208{
205 struct inline_list *ilist, *n; 209 struct a2l_data *a2l = dso->a2l;
210 char *funcname = a2l->funcname ? strdup(a2l->funcname) : NULL;
211 char *filename = a2l->filename ? strdup(a2l->filename) : NULL;
206 212
207 list_for_each_entry_safe_reverse(ilist, n, &node->val, list) 213 return inline_list__append(filename, funcname, a2l->line, node, dso);
208 list_move_tail(&ilist->list, &node->val);
209} 214}
210 215
211static int addr2line(const char *dso_name, u64 addr, 216static int addr2line(const char *dso_name, u64 addr,
@@ -230,36 +235,36 @@ static int addr2line(const char *dso_name, u64 addr,
230 235
231 bfd_map_over_sections(a2l->abfd, find_address_in_section, a2l); 236 bfd_map_over_sections(a2l->abfd, find_address_in_section, a2l);
232 237
233 if (a2l->found && unwind_inlines) { 238 if (!a2l->found)
239 return 0;
240
241 if (unwind_inlines) {
234 int cnt = 0; 242 int cnt = 0;
235 243
244 if (node && inline_list__append_dso_a2l(dso, node))
245 return 0;
246
236 while (bfd_find_inliner_info(a2l->abfd, &a2l->filename, 247 while (bfd_find_inliner_info(a2l->abfd, &a2l->filename,
237 &a2l->funcname, &a2l->line) && 248 &a2l->funcname, &a2l->line) &&
238 cnt++ < MAX_INLINE_NEST) { 249 cnt++ < MAX_INLINE_NEST) {
239 250
240 if (node != NULL) { 251 if (node != NULL) {
241 if (inline_list__append(strdup(a2l->filename), 252 if (inline_list__append_dso_a2l(dso, node))
242 strdup(a2l->funcname),
243 a2l->line, node,
244 dso) != 0)
245 return 0; 253 return 0;
254 // found at least one inline frame
255 ret = 1;
246 } 256 }
247 } 257 }
258 }
248 259
249 if ((node != NULL) && 260 if (file) {
250 (callchain_param.order != ORDER_CALLEE)) { 261 *file = a2l->filename ? strdup(a2l->filename) : NULL;
251 inline_list__reverse(node); 262 ret = *file ? 1 : 0;
252 }
253 } 263 }
254 264
255 if (a2l->found && a2l->filename) { 265 if (line)
256 *file = strdup(a2l->filename);
257 *line = a2l->line; 266 *line = a2l->line;
258 267
259 if (*file)
260 ret = 1;
261 }
262
263 return ret; 268 return ret;
264} 269}
265 270
@@ -278,8 +283,6 @@ void dso__free_a2l(struct dso *dso)
278static struct inline_node *addr2inlines(const char *dso_name, u64 addr, 283static struct inline_node *addr2inlines(const char *dso_name, u64 addr,
279 struct dso *dso) 284 struct dso *dso)
280{ 285{
281 char *file = NULL;
282 unsigned int line = 0;
283 struct inline_node *node; 286 struct inline_node *node;
284 287
285 node = zalloc(sizeof(*node)); 288 node = zalloc(sizeof(*node));
@@ -291,7 +294,7 @@ static struct inline_node *addr2inlines(const char *dso_name, u64 addr,
291 INIT_LIST_HEAD(&node->val); 294 INIT_LIST_HEAD(&node->val);
292 node->addr = addr; 295 node->addr = addr;
293 296
294 if (!addr2line(dso_name, addr, &file, &line, dso, TRUE, node)) 297 if (!addr2line(dso_name, addr, NULL, NULL, dso, TRUE, node))
295 goto out_free_inline_node; 298 goto out_free_inline_node;
296 299
297 if (list_empty(&node->val)) 300 if (list_empty(&node->val))
diff --git a/tools/perf/util/unwind-libdw.c b/tools/perf/util/unwind-libdw.c
index f90e11a555b2..943a06291587 100644
--- a/tools/perf/util/unwind-libdw.c
+++ b/tools/perf/util/unwind-libdw.c
@@ -168,12 +168,16 @@ frame_callback(Dwfl_Frame *state, void *arg)
168{ 168{
169 struct unwind_info *ui = arg; 169 struct unwind_info *ui = arg;
170 Dwarf_Addr pc; 170 Dwarf_Addr pc;
171 bool isactivation;
171 172
172 if (!dwfl_frame_pc(state, &pc, NULL)) { 173 if (!dwfl_frame_pc(state, &pc, &isactivation)) {
173 pr_err("%s", dwfl_errmsg(-1)); 174 pr_err("%s", dwfl_errmsg(-1));
174 return DWARF_CB_ABORT; 175 return DWARF_CB_ABORT;
175 } 176 }
176 177
178 if (!isactivation)
179 --pc;
180
177 return entry(pc, ui) || !(--ui->max_stack) ? 181 return entry(pc, ui) || !(--ui->max_stack) ?
178 DWARF_CB_ABORT : DWARF_CB_OK; 182 DWARF_CB_ABORT : DWARF_CB_OK;
179} 183}
diff --git a/tools/perf/util/unwind-libunwind-local.c b/tools/perf/util/unwind-libunwind-local.c
index f8455bed6e65..672c2ada9357 100644
--- a/tools/perf/util/unwind-libunwind-local.c
+++ b/tools/perf/util/unwind-libunwind-local.c
@@ -692,6 +692,17 @@ static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb,
692 692
693 while (!ret && (unw_step(&c) > 0) && i < max_stack) { 693 while (!ret && (unw_step(&c) > 0) && i < max_stack) {
694 unw_get_reg(&c, UNW_REG_IP, &ips[i]); 694 unw_get_reg(&c, UNW_REG_IP, &ips[i]);
695
696 /*
697 * Decrement the IP for any non-activation frames.
698 * this is required to properly find the srcline
699 * for caller frames.
700 * See also the documentation for dwfl_frame_pc(),
701 * which this code tries to replicate.
702 */
703 if (unw_is_signal_frame(&c) <= 0)
704 --ips[i];
705
695 ++i; 706 ++i;
696 } 707 }
697 708