|
@@ -144,9 +144,60 @@ static void callchain_list__set_folding(struct callchain_list *cl, bool unfold)
|
|
|
cl->unfolded = unfold ? cl->has_children : false;
|
|
|
}
|
|
|
|
|
|
+static struct inline_node *inline_node__create(struct map *map, u64 ip)
|
|
|
+{
|
|
|
+ struct dso *dso;
|
|
|
+ struct inline_node *node;
|
|
|
+
|
|
|
+ if (map == NULL)
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ dso = map->dso;
|
|
|
+ if (dso == NULL)
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ if (dso->kernel != DSO_TYPE_USER)
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ node = dso__parse_addr_inlines(dso,
|
|
|
+ map__rip_2objdump(map, ip));
|
|
|
+
|
|
|
+ return node;
|
|
|
+}
|
|
|
+
|
|
|
+static int inline__count_rows(struct inline_node *node)
|
|
|
+{
|
|
|
+ struct inline_list *ilist;
|
|
|
+ int i = 0;
|
|
|
+
|
|
|
+ if (node == NULL)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ list_for_each_entry(ilist, &node->val, list) {
|
|
|
+ if ((ilist->filename != NULL) || (ilist->funcname != NULL))
|
|
|
+ i++;
|
|
|
+ }
|
|
|
+
|
|
|
+ return i;
|
|
|
+}
|
|
|
+
|
|
|
+static int callchain_list__inline_rows(struct callchain_list *chain)
|
|
|
+{
|
|
|
+ struct inline_node *node;
|
|
|
+ int rows;
|
|
|
+
|
|
|
+ node = inline_node__create(chain->ms.map, chain->ip);
|
|
|
+ if (node == NULL)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ rows = inline__count_rows(node);
|
|
|
+ inline_node__delete(node);
|
|
|
+ return rows;
|
|
|
+}
|
|
|
+
|
|
|
static int callchain_node__count_rows_rb_tree(struct callchain_node *node)
|
|
|
{
|
|
|
- int n = 0;
|
|
|
+ int n = 0, inline_rows;
|
|
|
struct rb_node *nd;
|
|
|
|
|
|
for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
|
|
@@ -156,6 +207,13 @@ static int callchain_node__count_rows_rb_tree(struct callchain_node *node)
|
|
|
|
|
|
list_for_each_entry(chain, &child->val, list) {
|
|
|
++n;
|
|
|
+
|
|
|
+ if (symbol_conf.inline_name) {
|
|
|
+ inline_rows =
|
|
|
+ callchain_list__inline_rows(chain);
|
|
|
+ n += inline_rows;
|
|
|
+ }
|
|
|
+
|
|
|
/* We need this because we may not have children */
|
|
|
folded_sign = callchain_list__folded(chain);
|
|
|
if (folded_sign == '+')
|
|
@@ -207,7 +265,7 @@ static int callchain_node__count_rows(struct callchain_node *node)
|
|
|
{
|
|
|
struct callchain_list *chain;
|
|
|
bool unfolded = false;
|
|
|
- int n = 0;
|
|
|
+ int n = 0, inline_rows;
|
|
|
|
|
|
if (callchain_param.mode == CHAIN_FLAT)
|
|
|
return callchain_node__count_flat_rows(node);
|
|
@@ -216,6 +274,11 @@ static int callchain_node__count_rows(struct callchain_node *node)
|
|
|
|
|
|
list_for_each_entry(chain, &node->val, list) {
|
|
|
++n;
|
|
|
+ if (symbol_conf.inline_name) {
|
|
|
+ inline_rows = callchain_list__inline_rows(chain);
|
|
|
+ n += inline_rows;
|
|
|
+ }
|
|
|
+
|
|
|
unfolded = chain->unfolded;
|
|
|
}
|
|
|
|
|
@@ -362,6 +425,19 @@ static void hist_entry__init_have_children(struct hist_entry *he)
|
|
|
he->init_have_children = true;
|
|
|
}
|
|
|
|
|
|
+static void hist_entry_init_inline_node(struct hist_entry *he)
|
|
|
+{
|
|
|
+ if (he->inline_node)
|
|
|
+ return;
|
|
|
+
|
|
|
+ he->inline_node = inline_node__create(he->ms.map, he->ip);
|
|
|
+
|
|
|
+ if (he->inline_node == NULL)
|
|
|
+ return;
|
|
|
+
|
|
|
+ he->has_children = true;
|
|
|
+}
|
|
|
+
|
|
|
static bool hist_browser__toggle_fold(struct hist_browser *browser)
|
|
|
{
|
|
|
struct hist_entry *he = browser->he_selection;
|
|
@@ -393,7 +469,12 @@ static bool hist_browser__toggle_fold(struct hist_browser *browser)
|
|
|
|
|
|
if (he->unfolded) {
|
|
|
if (he->leaf)
|
|
|
- he->nr_rows = callchain__count_rows(&he->sorted_chain);
|
|
|
+ if (he->inline_node)
|
|
|
+ he->nr_rows = inline__count_rows(
|
|
|
+ he->inline_node);
|
|
|
+ else
|
|
|
+ he->nr_rows = callchain__count_rows(
|
|
|
+ &he->sorted_chain);
|
|
|
else
|
|
|
he->nr_rows = hierarchy_count_rows(browser, he, false);
|
|
|
|
|
@@ -753,6 +834,70 @@ static bool hist_browser__check_dump_full(struct hist_browser *browser __maybe_u
|
|
|
|
|
|
#define LEVEL_OFFSET_STEP 3
|
|
|
|
|
|
+static int hist_browser__show_inline(struct hist_browser *browser,
|
|
|
+ struct inline_node *node,
|
|
|
+ unsigned short row,
|
|
|
+ int offset)
|
|
|
+{
|
|
|
+ struct inline_list *ilist;
|
|
|
+ char buf[1024];
|
|
|
+ int color, width, first_row;
|
|
|
+
|
|
|
+ first_row = row;
|
|
|
+ width = browser->b.width - (LEVEL_OFFSET_STEP + 2);
|
|
|
+ list_for_each_entry(ilist, &node->val, list) {
|
|
|
+ if ((ilist->filename != NULL) || (ilist->funcname != NULL)) {
|
|
|
+ color = HE_COLORSET_NORMAL;
|
|
|
+ if (ui_browser__is_current_entry(&browser->b, row))
|
|
|
+ color = HE_COLORSET_SELECTED;
|
|
|
+
|
|
|
+ if (callchain_param.key == CCKEY_ADDRESS) {
|
|
|
+ if (ilist->filename != NULL)
|
|
|
+ scnprintf(buf, sizeof(buf),
|
|
|
+ "%s:%d (inline)",
|
|
|
+ ilist->filename,
|
|
|
+ ilist->line_nr);
|
|
|
+ else
|
|
|
+ scnprintf(buf, sizeof(buf), "??");
|
|
|
+ } else if (ilist->funcname != NULL)
|
|
|
+ scnprintf(buf, sizeof(buf), "%s (inline)",
|
|
|
+ ilist->funcname);
|
|
|
+ else if (ilist->filename != NULL)
|
|
|
+ scnprintf(buf, sizeof(buf),
|
|
|
+ "%s:%d (inline)",
|
|
|
+ ilist->filename,
|
|
|
+ ilist->line_nr);
|
|
|
+ else
|
|
|
+ scnprintf(buf, sizeof(buf), "??");
|
|
|
+
|
|
|
+ ui_browser__set_color(&browser->b, color);
|
|
|
+ hist_browser__gotorc(browser, row, 0);
|
|
|
+ ui_browser__write_nstring(&browser->b, " ",
|
|
|
+ LEVEL_OFFSET_STEP + offset);
|
|
|
+ ui_browser__write_nstring(&browser->b, buf, width);
|
|
|
+ row++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return row - first_row;
|
|
|
+}
|
|
|
+
|
|
|
+static size_t show_inline_list(struct hist_browser *browser, struct map *map,
|
|
|
+ u64 ip, int row, int offset)
|
|
|
+{
|
|
|
+ struct inline_node *node;
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ node = inline_node__create(map, ip);
|
|
|
+ if (node == NULL)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ ret = hist_browser__show_inline(browser, node, row, offset);
|
|
|
+
|
|
|
+ inline_node__delete(node);
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
static int hist_browser__show_callchain_list(struct hist_browser *browser,
|
|
|
struct callchain_node *node,
|
|
|
struct callchain_list *chain,
|
|
@@ -764,6 +909,7 @@ static int hist_browser__show_callchain_list(struct hist_browser *browser,
|
|
|
char bf[1024], *alloc_str;
|
|
|
char buf[64], *alloc_str2;
|
|
|
const char *str;
|
|
|
+ int inline_rows = 0, ret = 1;
|
|
|
|
|
|
if (arg->row_offset != 0) {
|
|
|
arg->row_offset--;
|
|
@@ -801,10 +947,15 @@ static int hist_browser__show_callchain_list(struct hist_browser *browser,
|
|
|
}
|
|
|
|
|
|
print(browser, chain, str, offset, row, arg);
|
|
|
-
|
|
|
free(alloc_str);
|
|
|
free(alloc_str2);
|
|
|
- return 1;
|
|
|
+
|
|
|
+ if (symbol_conf.inline_name) {
|
|
|
+ inline_rows = show_inline_list(browser, chain->ms.map,
|
|
|
+ chain->ip, row + 1, offset);
|
|
|
+ }
|
|
|
+
|
|
|
+ return ret + inline_rows;
|
|
|
}
|
|
|
|
|
|
static bool check_percent_display(struct rb_node *node, u64 parent_total)
|
|
@@ -1228,6 +1379,12 @@ static int hist_browser__show_entry(struct hist_browser *browser,
|
|
|
folded_sign = hist_entry__folded(entry);
|
|
|
}
|
|
|
|
|
|
+ if (symbol_conf.inline_name &&
|
|
|
+ (!entry->has_children)) {
|
|
|
+ hist_entry_init_inline_node(entry);
|
|
|
+ folded_sign = hist_entry__folded(entry);
|
|
|
+ }
|
|
|
+
|
|
|
if (row_offset == 0) {
|
|
|
struct hpp_arg arg = {
|
|
|
.b = &browser->b,
|
|
@@ -1259,7 +1416,8 @@ static int hist_browser__show_entry(struct hist_browser *browser,
|
|
|
}
|
|
|
|
|
|
if (first) {
|
|
|
- if (symbol_conf.use_callchain) {
|
|
|
+ if (symbol_conf.use_callchain ||
|
|
|
+ symbol_conf.inline_name) {
|
|
|
ui_browser__printf(&browser->b, "%c ", folded_sign);
|
|
|
width -= 2;
|
|
|
}
|
|
@@ -1301,8 +1459,14 @@ static int hist_browser__show_entry(struct hist_browser *browser,
|
|
|
.is_current_entry = current_entry,
|
|
|
};
|
|
|
|
|
|
- printed += hist_browser__show_callchain(browser, entry, 1, row,
|
|
|
- hist_browser__show_callchain_entry, &arg,
|
|
|
+ if (entry->inline_node)
|
|
|
+ printed += hist_browser__show_inline(browser,
|
|
|
+ entry->inline_node, row, 0);
|
|
|
+ else
|
|
|
+ printed += hist_browser__show_callchain(browser,
|
|
|
+ entry, 1, row,
|
|
|
+ hist_browser__show_callchain_entry,
|
|
|
+ &arg,
|
|
|
hist_browser__check_output_full);
|
|
|
}
|
|
|
|