162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci#include <elf.h> 362306a36Sopenharmony_ci#include <inttypes.h> 462306a36Sopenharmony_ci#include <sys/ttydefaults.h> 562306a36Sopenharmony_ci#include <stdlib.h> 662306a36Sopenharmony_ci#include <string.h> 762306a36Sopenharmony_ci#include <linux/bitops.h> 862306a36Sopenharmony_ci#include "../../util/debug.h" 962306a36Sopenharmony_ci#include "../../util/map.h" 1062306a36Sopenharmony_ci#include "../../util/dso.h" 1162306a36Sopenharmony_ci#include "../../util/symbol.h" 1262306a36Sopenharmony_ci#include "../browser.h" 1362306a36Sopenharmony_ci#include "../helpline.h" 1462306a36Sopenharmony_ci#include "../keysyms.h" 1562306a36Sopenharmony_ci#include "map.h" 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include <linux/ctype.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_cistruct map_browser { 2062306a36Sopenharmony_ci struct ui_browser b; 2162306a36Sopenharmony_ci struct map *map; 2262306a36Sopenharmony_ci u8 addrlen; 2362306a36Sopenharmony_ci}; 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_cistatic void map_browser__write(struct ui_browser *browser, void *nd, int row) 2662306a36Sopenharmony_ci{ 2762306a36Sopenharmony_ci struct symbol *sym = rb_entry(nd, struct symbol, rb_node); 2862306a36Sopenharmony_ci struct map_browser *mb = container_of(browser, struct map_browser, b); 2962306a36Sopenharmony_ci bool current_entry = ui_browser__is_current_entry(browser, row); 3062306a36Sopenharmony_ci int width; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci ui_browser__set_percent_color(browser, 0, current_entry); 3362306a36Sopenharmony_ci ui_browser__printf(browser, "%*" PRIx64 " %*" PRIx64 " %c ", 3462306a36Sopenharmony_ci mb->addrlen, sym->start, mb->addrlen, sym->end, 3562306a36Sopenharmony_ci sym->binding == STB_GLOBAL ? 'g' : 3662306a36Sopenharmony_ci sym->binding == STB_LOCAL ? 'l' : 'w'); 3762306a36Sopenharmony_ci width = browser->width - ((mb->addrlen * 2) + 4); 3862306a36Sopenharmony_ci if (width > 0) 3962306a36Sopenharmony_ci ui_browser__write_nstring(browser, sym->name, width); 4062306a36Sopenharmony_ci} 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci/* FIXME uber-kludgy, see comment on cmd_report... */ 4362306a36Sopenharmony_cistatic u32 *symbol__browser_index(struct symbol *browser) 4462306a36Sopenharmony_ci{ 4562306a36Sopenharmony_ci return ((void *)browser) - sizeof(struct rb_node) - sizeof(u32); 4662306a36Sopenharmony_ci} 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_cistatic int map_browser__search(struct map_browser *browser) 4962306a36Sopenharmony_ci{ 5062306a36Sopenharmony_ci char target[512]; 5162306a36Sopenharmony_ci struct symbol *sym; 5262306a36Sopenharmony_ci int err = ui_browser__input_window("Search by name/addr", 5362306a36Sopenharmony_ci "Prefix with 0x to search by address", 5462306a36Sopenharmony_ci target, "ENTER: OK, ESC: Cancel", 0); 5562306a36Sopenharmony_ci if (err != K_ENTER) 5662306a36Sopenharmony_ci return -1; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci if (target[0] == '0' && tolower(target[1]) == 'x') { 5962306a36Sopenharmony_ci u64 addr = strtoull(target, NULL, 16); 6062306a36Sopenharmony_ci sym = map__find_symbol(browser->map, addr); 6162306a36Sopenharmony_ci } else 6262306a36Sopenharmony_ci sym = map__find_symbol_by_name(browser->map, target); 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci if (sym != NULL) { 6562306a36Sopenharmony_ci u32 *idx = symbol__browser_index(sym); 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci browser->b.top = &sym->rb_node; 6862306a36Sopenharmony_ci browser->b.index = browser->b.top_idx = *idx; 6962306a36Sopenharmony_ci } else 7062306a36Sopenharmony_ci ui_helpline__fpush("%s not found!", target); 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci return 0; 7362306a36Sopenharmony_ci} 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_cistatic int map_browser__run(struct map_browser *browser) 7662306a36Sopenharmony_ci{ 7762306a36Sopenharmony_ci int key; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci if (ui_browser__show(&browser->b, map__dso(browser->map)->long_name, 8062306a36Sopenharmony_ci "Press ESC to exit, %s / to search", 8162306a36Sopenharmony_ci verbose > 0 ? "" : "restart with -v to use") < 0) 8262306a36Sopenharmony_ci return -1; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci while (1) { 8562306a36Sopenharmony_ci key = ui_browser__run(&browser->b, 0); 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci switch (key) { 8862306a36Sopenharmony_ci case '/': 8962306a36Sopenharmony_ci if (verbose > 0) 9062306a36Sopenharmony_ci map_browser__search(browser); 9162306a36Sopenharmony_ci default: 9262306a36Sopenharmony_ci break; 9362306a36Sopenharmony_ci case K_LEFT: 9462306a36Sopenharmony_ci case K_ESC: 9562306a36Sopenharmony_ci case 'q': 9662306a36Sopenharmony_ci case CTRL('c'): 9762306a36Sopenharmony_ci goto out; 9862306a36Sopenharmony_ci } 9962306a36Sopenharmony_ci } 10062306a36Sopenharmony_ciout: 10162306a36Sopenharmony_ci ui_browser__hide(&browser->b); 10262306a36Sopenharmony_ci return key; 10362306a36Sopenharmony_ci} 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ciint map__browse(struct map *map) 10662306a36Sopenharmony_ci{ 10762306a36Sopenharmony_ci struct map_browser mb = { 10862306a36Sopenharmony_ci .b = { 10962306a36Sopenharmony_ci .entries = &map__dso(map)->symbols, 11062306a36Sopenharmony_ci .refresh = ui_browser__rb_tree_refresh, 11162306a36Sopenharmony_ci .seek = ui_browser__rb_tree_seek, 11262306a36Sopenharmony_ci .write = map_browser__write, 11362306a36Sopenharmony_ci }, 11462306a36Sopenharmony_ci .map = map, 11562306a36Sopenharmony_ci }; 11662306a36Sopenharmony_ci struct rb_node *nd; 11762306a36Sopenharmony_ci char tmp[BITS_PER_LONG / 4]; 11862306a36Sopenharmony_ci u64 maxaddr = 0; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci for (nd = rb_first(mb.b.entries); nd; nd = rb_next(nd)) { 12162306a36Sopenharmony_ci struct symbol *pos = rb_entry(nd, struct symbol, rb_node); 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci if (maxaddr < pos->end) 12462306a36Sopenharmony_ci maxaddr = pos->end; 12562306a36Sopenharmony_ci if (verbose > 0) { 12662306a36Sopenharmony_ci u32 *idx = symbol__browser_index(pos); 12762306a36Sopenharmony_ci *idx = mb.b.nr_entries; 12862306a36Sopenharmony_ci } 12962306a36Sopenharmony_ci ++mb.b.nr_entries; 13062306a36Sopenharmony_ci } 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci mb.addrlen = snprintf(tmp, sizeof(tmp), "%" PRIx64, maxaddr); 13362306a36Sopenharmony_ci return map_browser__run(&mb); 13462306a36Sopenharmony_ci} 135