1e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "../libslang.h"
2e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include <elf.h>
3e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include <inttypes.h>
4e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include <sys/ttydefaults.h>
5e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include <string.h>
6e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include <linux/bitops.h>
7e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "../../util/util.h"
8e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "../../util/debug.h"
9e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "../../util/symbol.h"
10e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "../browser.h"
11e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "../helpline.h"
12e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "../keysyms.h"
13e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "map.h"
14e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
15e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstruct map_browser {
16e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct ui_browser b;
17e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct map	  *map;
18e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	u8		  addrlen;
19e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng};
20e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
21e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic void map_browser__write(struct ui_browser *self, void *nd, int row)
22e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
23e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
24e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct map_browser *mb = container_of(self, struct map_browser, b);
25e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	bool current_entry = ui_browser__is_current_entry(self, row);
26e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int width;
27e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
28e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	ui_browser__set_percent_color(self, 0, current_entry);
29e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	slsmg_printf("%*" PRIx64 " %*" PRIx64 " %c ",
30e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		     mb->addrlen, sym->start, mb->addrlen, sym->end,
31e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		     sym->binding == STB_GLOBAL ? 'g' :
32e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		     sym->binding == STB_LOCAL  ? 'l' : 'w');
33e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	width = self->width - ((mb->addrlen * 2) + 4);
34e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (width > 0)
35e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		slsmg_write_nstring(sym->name, width);
36e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
37e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
38e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng/* FIXME uber-kludgy, see comment on cmd_report... */
39e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic u32 *symbol__browser_index(struct symbol *self)
40e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
41e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return ((void *)self) - sizeof(struct rb_node) - sizeof(u32);
42e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
43e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
44e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int map_browser__search(struct map_browser *self)
45e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
46e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	char target[512];
47e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct symbol *sym;
48e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int err = ui_browser__input_window("Search by name/addr",
49e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					   "Prefix with 0x to search by address",
50e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng					   target, "ENTER: OK, ESC: Cancel", 0);
51e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (err != K_ENTER)
52e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return -1;
53e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
54e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (target[0] == '0' && tolower(target[1]) == 'x') {
55e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		u64 addr = strtoull(target, NULL, 16);
56e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		sym = map__find_symbol(self->map, addr, NULL);
57e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	} else
58e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		sym = map__find_symbol_by_name(self->map, target, NULL);
59e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
60e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (sym != NULL) {
61e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		u32 *idx = symbol__browser_index(sym);
62e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
63e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		self->b.top = &sym->rb_node;
64e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		self->b.index = self->b.top_idx = *idx;
65e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	} else
66e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		ui_helpline__fpush("%s not found!", target);
67e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
68e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return 0;
69e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
70e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
71e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int map_browser__run(struct map_browser *self)
72e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
73e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int key;
74e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
75e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (ui_browser__show(&self->b, self->map->dso->long_name,
76e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			     "Press <- or ESC to exit, %s / to search",
77e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			     verbose ? "" : "restart with -v to use") < 0)
78e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return -1;
79e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
80e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	while (1) {
81e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		key = ui_browser__run(&self->b, 0);
82e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
83e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		switch (key) {
84e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		case '/':
85e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			if (verbose)
86e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng				map_browser__search(self);
87e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		default:
88e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			break;
89e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng                case K_LEFT:
90e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng                case K_ESC:
91e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng                case 'q':
92e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng                case CTRL('c'):
93e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng                        goto out;
94e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		}
95e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
96e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengout:
97e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	ui_browser__hide(&self->b);
98e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return key;
99e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
100e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
101e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengint map__browse(struct map *self)
102e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
103e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct map_browser mb = {
104e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		.b = {
105e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			.entries = &self->dso->symbols[self->type],
106e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			.refresh = ui_browser__rb_tree_refresh,
107e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			.seek	 = ui_browser__rb_tree_seek,
108e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			.write	 = map_browser__write,
109e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		},
110e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		.map = self,
111e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	};
112e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct rb_node *nd;
113e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	char tmp[BITS_PER_LONG / 4];
114e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	u64 maxaddr = 0;
115e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
116e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	for (nd = rb_first(mb.b.entries); nd; nd = rb_next(nd)) {
117e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
118e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
119e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (maxaddr < pos->end)
120e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			maxaddr = pos->end;
121e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		if (verbose) {
122e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			u32 *idx = symbol__browser_index(pos);
123e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			*idx = mb.b.nr_entries;
124e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		}
125e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		++mb.b.nr_entries;
126e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
127e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
128e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	mb.addrlen = snprintf(tmp, sizeof(tmp), "%" PRIx64, maxaddr);
129e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return map_browser__run(&mb);
130e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
131