summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--tools/perf/util/newt.c129
1 files changed, 127 insertions, 2 deletions
diff --git a/tools/perf/util/newt.c b/tools/perf/util/newt.c
index 91de99b58445..fc4a2b3aa65e 100644
--- a/tools/perf/util/newt.c
+++ b/tools/perf/util/newt.c
@@ -13,6 +13,7 @@
#include <slang.h>
#include <signal.h>
#include <stdlib.h>
+#include <elf.h>
#include <newt.h>
#include <sys/ttydefaults.h>
@@ -280,6 +281,7 @@ struct ui_browser {
u16 top, left, width, height;
void *priv;
unsigned int (*refresh_entries)(struct ui_browser *self);
+ void (*write)(struct ui_browser *self, void *entry, int row);
void (*seek)(struct ui_browser *self,
off_t offset, int whence);
u32 nr_entries;
@@ -316,6 +318,58 @@ static void ui_browser__list_head_seek(struct ui_browser *self,
self->first_visible_entry = pos;
}
+static void ui_browser__rb_tree_seek(struct ui_browser *self,
+ off_t offset, int whence)
+{
+ struct rb_root *root = self->entries;
+ struct rb_node *nd;
+
+ switch (whence) {
+ case SEEK_SET:
+ nd = rb_first(root);
+ break;
+ case SEEK_CUR:
+ nd = self->first_visible_entry;
+ break;
+ case SEEK_END:
+ nd = rb_last(root);
+ break;
+ default:
+ return;
+ }
+
+ if (offset > 0) {
+ while (offset-- != 0)
+ nd = rb_next(nd);
+ } else {
+ while (offset++ != 0)
+ nd = rb_prev(nd);
+ }
+
+ self->first_visible_entry = nd;
+}
+
+static unsigned int ui_browser__rb_tree_refresh(struct ui_browser *self)
+{
+ struct rb_node *nd;
+ int row = 0;
+
+ if (self->first_visible_entry == NULL)
+ self->first_visible_entry = rb_first(self->entries);
+
+ nd = self->first_visible_entry;
+
+ while (nd != NULL) {
+ SLsmg_gotorc(self->top + row, self->left);
+ self->write(self, nd, row);
+ if (++row == self->height)
+ break;
+ nd = rb_next(nd);
+ }
+
+ return row;
+}
+
static bool ui_browser__is_current_entry(struct ui_browser *self, unsigned row)
{
return (self->first_visible_entry_idx + row) == self->index;
@@ -592,6 +646,70 @@ int hist_entry__tui_annotate(struct hist_entry *self)
return ret;
}
+/* -------------------------------------------------------------------- */
+
+struct map_browser {
+ struct ui_browser b;
+ struct map *map;
+ u16 namelen;
+ u8 addrlen;
+};
+
+static void map_browser__write(struct ui_browser *self, void *nd, int row)
+{
+ struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
+ struct map_browser *mb = container_of(self, struct map_browser, b);
+ bool current_entry = ui_browser__is_current_entry(self, row);
+ int color = ui_browser__percent_color(0, current_entry);
+
+ SLsmg_set_color(color);
+ slsmg_printf("%*llx %*llx %c ",
+ mb->addrlen, sym->start, mb->addrlen, sym->end,
+ sym->binding == STB_GLOBAL ? 'g' :
+ sym->binding == STB_LOCAL ? 'l' : 'w');
+ slsmg_write_nstring(sym->name, mb->namelen);
+}
+
+static int map__browse(struct map *self)
+{
+ struct map_browser mb = {
+ .b = {
+ .entries = &self->dso->symbols[self->type],
+ .refresh_entries = ui_browser__rb_tree_refresh,
+ .seek = ui_browser__rb_tree_seek,
+ .write = map_browser__write,
+ },
+ };
+ struct newtExitStruct es;
+ struct rb_node *nd;
+ char tmp[BITS_PER_LONG / 4];
+ u64 maxaddr = 0;
+ int ret;
+
+ ui_helpline__push("Press <- or ESC to exit");
+
+ for (nd = rb_first(mb.b.entries); nd; nd = rb_next(nd)) {
+ struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
+
+ if (mb.namelen < pos->namelen)
+ mb.namelen = pos->namelen;
+ if (maxaddr < pos->end)
+ maxaddr = pos->end;
+ ++mb.b.nr_entries;
+ }
+
+ mb.addrlen = snprintf(tmp, sizeof(tmp), "%llx", maxaddr);
+ mb.b.width += mb.addrlen * 2 + 4 + mb.namelen;
+ ui_browser__show(&mb.b, self->dso->long_name);
+ ret = ui_browser__run(&mb.b, &es);
+ newtFormDestroy(mb.b.form);
+ newtPopWindow();
+ ui_helpline__pop();
+ return ret;
+}
+
+/* -------------------------------------------------------------------- */
+
struct hist_browser {
struct ui_browser b;
struct hists *hists;
@@ -680,7 +798,8 @@ int hists__browse(struct hists *self, const char *helpline, const char *ev_name)
const struct dso *dso;
char *options[16];
int nr_options = 0, choice = 0, i,
- annotate = -2, zoom_dso = -2, zoom_thread = -2;
+ annotate = -2, zoom_dso = -2, zoom_thread = -2,
+ browse_map = -2;
if (hist_browser__run(browser, msg, &es))
break;
@@ -771,6 +890,10 @@ do_help:
(dso->kernel ? "the Kernel" : dso->short_name)) > 0)
zoom_dso = nr_options++;
+ if (browser->selection->map != NULL &&
+ asprintf(&options[nr_options], "Browse map details") > 0)
+ browse_map = nr_options++;
+
options[nr_options++] = (char *)"Exit";
choice = popup_menu(nr_options, options);
@@ -800,7 +923,9 @@ do_annotate:
continue;
hist_entry__tui_annotate(he);
- } else if (choice == zoom_dso) {
+ } else if (choice == browse_map)
+ map__browse(browser->selection->map);
+ else if (choice == zoom_dso) {
zoom_dso:
if (dso_filter) {
pstack__remove(fstack, &dso_filter);