mirror of
https://github.com/FEX-Emu/linux.git
synced 2024-12-28 12:25:31 +00:00
Arjan & Linus Annotation Edition
More like Linus', but hey at least an attempt at implementing a suggestion by Arjan made this time around! . Fix indirect calls beautifier, reported by Linus. . Use the objdump comments to nuke specificities about how access to a well know variable is encoded, suggested by Linus. . Show the number of places that jump to a target, requested by Arjan. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.14 (GNU/Linux) iQIcBAABAgAGBQJPrr3pAAoJENZQFvNTUqpAUZUP/jbBfYzJPqFWNvpPrTIeJXAP WVX8bOHCjSQId9dWrc/Nlf/25JUbZOnDE8FV9weBGjJfgc6Y7awfuVtFW/QNjZ7w 2Hggn5242J+CSJ8jwLFFV3gJH3jQUE7m6egkkCQBdPI/ruarO01FKfydHvkTeSNt f418A+S2Bx6oEjZa+DO8g/bhJ9d4FbS5hqubWvqC6iTf5Z9+6fTNnR0dJG1GTdy6 F8x7SXNG3AXKHNbqVzdXExtOYS2bum9yQNI/O4sjUgSoOdg7GzPYom08WglxnOkO K8BXj8stbEW3mZJANoNxUzR7xvfvcaBsEWmz8gF/LkZa51VnbtSsrqKkKZU8LuJ6 MRBW9ue2BUrtLb+U9sfFSs1toRT8WfIetK7OXJIow6m+5TZBepWhZt+Gx0c1LCrt AOGvGSq1u0troomv52JYqNukI+w39quWBPk4C7/kKGY3SRjrriKyCyo1spJxH5en UVFQ8vEHu4gEUspXphKqctT4RAlBO2YdeiJv7t5h2TJgz9wnUwjnvrB1xpIvc6Yo 2gNjSMReNupT5mL8peh0eYS4+4Dcx14Layl3JeYPZ+azIf2mJrfpGucEv/s1b3yr XK2HAQboNF/eZSsuJsmbvq/BIOHaUjFMNqLw8ORwK0WnPNNO0iAuYnu45KcfXhTx I+9JzyG3WYJtZp+R7Zqg =cE1R -----END PGP SIGNATURE----- Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core Arjan & Linus Annotation Edition - Fix indirect calls beautifier, reported by Linus. - Use the objdump comments to nuke specificities about how access to a well know variable is encoded, suggested by Linus. - Show the number of places that jump to a target, requested by Arjan. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
commit
0c5a0f96e8
@ -16,7 +16,7 @@ struct browser_disasm_line {
|
||||
double percent;
|
||||
u32 idx;
|
||||
int idx_asm;
|
||||
bool jump_target;
|
||||
int jump_sources;
|
||||
};
|
||||
|
||||
struct annotate_browser {
|
||||
@ -28,11 +28,16 @@ struct annotate_browser {
|
||||
u64 start;
|
||||
int nr_asm_entries;
|
||||
int nr_entries;
|
||||
int max_jump_sources;
|
||||
int nr_jumps;
|
||||
bool hide_src_code;
|
||||
bool use_offset;
|
||||
bool jump_arrows;
|
||||
bool show_nr_jumps;
|
||||
bool searching_backwards;
|
||||
u8 addr_width;
|
||||
u8 jumps_width;
|
||||
u8 target_width;
|
||||
u8 min_addr_width;
|
||||
u8 max_addr_width;
|
||||
char search_bf[128];
|
||||
@ -55,6 +60,25 @@ static bool disasm_line__filter(struct ui_browser *browser, void *entry)
|
||||
return false;
|
||||
}
|
||||
|
||||
static int annotate_browser__jumps_percent_color(struct annotate_browser *browser,
|
||||
int nr, bool current)
|
||||
{
|
||||
if (current && (!browser->b.use_navkeypressed || browser->b.navkeypressed))
|
||||
return HE_COLORSET_SELECTED;
|
||||
if (nr == browser->max_jump_sources)
|
||||
return HE_COLORSET_TOP;
|
||||
if (nr > 1)
|
||||
return HE_COLORSET_MEDIUM;
|
||||
return HE_COLORSET_NORMAL;
|
||||
}
|
||||
|
||||
static int annotate_browser__set_jumps_percent_color(struct annotate_browser *browser,
|
||||
int nr, bool current)
|
||||
{
|
||||
int color = annotate_browser__jumps_percent_color(browser, nr, current);
|
||||
return ui_browser__set_color(&browser->b, color);
|
||||
}
|
||||
|
||||
static void annotate_browser__write(struct ui_browser *self, void *entry, int row)
|
||||
{
|
||||
struct annotate_browser *ab = container_of(self, struct annotate_browser, b);
|
||||
@ -98,9 +122,20 @@ static void annotate_browser__write(struct ui_browser *self, void *entry, int ro
|
||||
if (!ab->use_offset) {
|
||||
printed = scnprintf(bf, sizeof(bf), "%" PRIx64 ": ", addr);
|
||||
} else {
|
||||
if (bdl->jump_target) {
|
||||
if (bdl->jump_sources) {
|
||||
if (ab->show_nr_jumps) {
|
||||
int prev;
|
||||
printed = scnprintf(bf, sizeof(bf), "%*d ",
|
||||
ab->jumps_width,
|
||||
bdl->jump_sources);
|
||||
prev = annotate_browser__set_jumps_percent_color(ab, bdl->jump_sources,
|
||||
current_entry);
|
||||
slsmg_write_nstring(bf, printed);
|
||||
ui_browser__set_color(self, prev);
|
||||
}
|
||||
|
||||
printed = scnprintf(bf, sizeof(bf), "%*" PRIx64 ": ",
|
||||
ab->addr_width, addr);
|
||||
ab->target_width, addr);
|
||||
} else {
|
||||
printed = scnprintf(bf, sizeof(bf), "%*s ",
|
||||
ab->addr_width, " ");
|
||||
@ -546,10 +581,7 @@ static int annotate_browser__run(struct annotate_browser *self, int evidx,
|
||||
struct rb_node *nd = NULL;
|
||||
struct map_symbol *ms = self->b.priv;
|
||||
struct symbol *sym = ms->sym;
|
||||
const char *help = "<-/ESC: Exit, TAB/shift+TAB: Cycle hot lines, "
|
||||
"H: Hottest line, ->/ENTER: Line action, "
|
||||
"O: Offset view, "
|
||||
"S: Source view";
|
||||
const char *help = "Press 'h' for help on key bindings";
|
||||
int key;
|
||||
|
||||
if (ui_browser__show(&self->b, sym->name, help) < 0)
|
||||
@ -602,26 +634,47 @@ static int annotate_browser__run(struct annotate_browser *self, int evidx,
|
||||
else
|
||||
nd = self->curr_hot;
|
||||
break;
|
||||
case 'H':
|
||||
case K_F1:
|
||||
case 'h':
|
||||
ui_browser__help_window(&self->b,
|
||||
"UP/DOWN/PGUP\n"
|
||||
"PGDN/SPACE Navigate\n"
|
||||
"q/ESC/CTRL+C Exit\n\n"
|
||||
"-> Go to target\n"
|
||||
"<- Exit\n"
|
||||
"h Cycle thru hottest instructions\n"
|
||||
"j Toggle showing jump to target arrows\n"
|
||||
"J Toggle showing number of jump sources on targets\n"
|
||||
"n Search next string\n"
|
||||
"o Toggle disassembler output/simplified view\n"
|
||||
"s Toggle source code view\n"
|
||||
"/ Search string\n"
|
||||
"? Search previous string\n");
|
||||
continue;
|
||||
case 'H':
|
||||
nd = self->curr_hot;
|
||||
break;
|
||||
case 'S':
|
||||
case 's':
|
||||
if (annotate_browser__toggle_source(self))
|
||||
ui_helpline__puts(help);
|
||||
continue;
|
||||
case 'O':
|
||||
case 'o':
|
||||
self->use_offset = !self->use_offset;
|
||||
if (self->use_offset)
|
||||
self->addr_width = self->min_addr_width;
|
||||
self->target_width = self->min_addr_width;
|
||||
else
|
||||
self->addr_width = self->max_addr_width;
|
||||
self->target_width = self->max_addr_width;
|
||||
update_addr_width:
|
||||
self->addr_width = self->target_width;
|
||||
if (self->show_nr_jumps)
|
||||
self->addr_width += self->jumps_width + 1;
|
||||
continue;
|
||||
case 'j':
|
||||
self->jump_arrows = !self->jump_arrows;
|
||||
continue;
|
||||
case 'J':
|
||||
self->show_nr_jumps = !self->show_nr_jumps;
|
||||
goto update_addr_width;
|
||||
case '/':
|
||||
if (annotate_browser__search(self, delay_secs)) {
|
||||
show_help:
|
||||
@ -707,11 +760,23 @@ static void annotate_browser__mark_jump_targets(struct annotate_browser *browser
|
||||
continue;
|
||||
|
||||
bdlt = disasm_line__browser(dlt);
|
||||
bdlt->jump_target = true;
|
||||
if (++bdlt->jump_sources > browser->max_jump_sources)
|
||||
browser->max_jump_sources = bdlt->jump_sources;
|
||||
|
||||
++browser->nr_jumps;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static inline int width_jumps(int n)
|
||||
{
|
||||
if (n >= 100)
|
||||
return 5;
|
||||
if (n / 10)
|
||||
return 2;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
|
||||
void(*timer)(void *arg), void *arg,
|
||||
int delay_secs)
|
||||
@ -784,8 +849,9 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
|
||||
|
||||
annotate_browser__mark_jump_targets(&browser, size);
|
||||
|
||||
browser.addr_width = browser.min_addr_width = hex_width(size);
|
||||
browser.addr_width = browser.target_width = browser.min_addr_width = hex_width(size);
|
||||
browser.max_addr_width = hex_width(sym->end);
|
||||
browser.jumps_width = width_jumps(browser.max_jump_sources);
|
||||
browser.b.nr_entries = browser.nr_entries;
|
||||
browser.b.entries = ¬es->src->source,
|
||||
browser.b.width += 18; /* Percentage */
|
||||
|
@ -18,6 +18,17 @@
|
||||
|
||||
const char *disassembler_style;
|
||||
|
||||
static struct ins *ins__find(const char *name);
|
||||
static int disasm_line__parse(char *line, char **namep, char **rawp);
|
||||
|
||||
static void ins__delete(struct ins_operands *ops)
|
||||
{
|
||||
free(ops->source.raw);
|
||||
free(ops->source.name);
|
||||
free(ops->target.raw);
|
||||
free(ops->target.name);
|
||||
}
|
||||
|
||||
static int ins__raw_scnprintf(struct ins *ins, char *bf, size_t size,
|
||||
struct ins_operands *ops)
|
||||
{
|
||||
@ -56,6 +67,12 @@ static int call__parse(struct ins_operands *ops)
|
||||
return ops->target.name == NULL ? -1 : 0;
|
||||
|
||||
indirect_call:
|
||||
tok = strchr(endptr, '(');
|
||||
if (tok != NULL) {
|
||||
ops->target.addr = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
tok = strchr(endptr, '*');
|
||||
if (tok == NULL)
|
||||
return -1;
|
||||
@ -70,6 +87,9 @@ static int call__scnprintf(struct ins *ins, char *bf, size_t size,
|
||||
if (ops->target.name)
|
||||
return scnprintf(bf, size, "%-6.6s %s", ins->name, ops->target.name);
|
||||
|
||||
if (ops->target.addr == 0)
|
||||
return ins__raw_scnprintf(ins, bf, size, ops);
|
||||
|
||||
return scnprintf(bf, size, "%-6.6s *%" PRIx64, ins->name, ops->target.addr);
|
||||
}
|
||||
|
||||
@ -113,6 +133,185 @@ bool ins__is_jump(const struct ins *ins)
|
||||
return ins->ops == &jump_ops;
|
||||
}
|
||||
|
||||
static int comment__symbol(char *raw, char *comment, u64 *addrp, char **namep)
|
||||
{
|
||||
char *endptr, *name, *t;
|
||||
|
||||
if (strstr(raw, "(%rip)") == NULL)
|
||||
return 0;
|
||||
|
||||
*addrp = strtoull(comment, &endptr, 16);
|
||||
name = strchr(endptr, '<');
|
||||
if (name == NULL)
|
||||
return -1;
|
||||
|
||||
name++;
|
||||
|
||||
t = strchr(name, '>');
|
||||
if (t == NULL)
|
||||
return 0;
|
||||
|
||||
*t = '\0';
|
||||
*namep = strdup(name);
|
||||
*t = '>';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lock__parse(struct ins_operands *ops)
|
||||
{
|
||||
char *name;
|
||||
|
||||
ops->locked.ops = zalloc(sizeof(*ops->locked.ops));
|
||||
if (ops->locked.ops == NULL)
|
||||
return 0;
|
||||
|
||||
if (disasm_line__parse(ops->raw, &name, &ops->locked.ops->raw) < 0)
|
||||
goto out_free_ops;
|
||||
|
||||
ops->locked.ins = ins__find(name);
|
||||
if (ops->locked.ins == NULL)
|
||||
goto out_free_ops;
|
||||
|
||||
if (!ops->locked.ins->ops)
|
||||
return 0;
|
||||
|
||||
if (ops->locked.ins->ops->parse)
|
||||
ops->locked.ins->ops->parse(ops->locked.ops);
|
||||
|
||||
return 0;
|
||||
|
||||
out_free_ops:
|
||||
free(ops->locked.ops);
|
||||
ops->locked.ops = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lock__scnprintf(struct ins *ins, char *bf, size_t size,
|
||||
struct ins_operands *ops)
|
||||
{
|
||||
int printed;
|
||||
|
||||
if (ops->locked.ins == NULL)
|
||||
return ins__raw_scnprintf(ins, bf, size, ops);
|
||||
|
||||
printed = scnprintf(bf, size, "%-6.6s ", ins->name);
|
||||
return printed + ins__scnprintf(ops->locked.ins, bf + printed,
|
||||
size - printed, ops->locked.ops);
|
||||
}
|
||||
|
||||
static void lock__delete(struct ins_operands *ops)
|
||||
{
|
||||
free(ops->locked.ops);
|
||||
free(ops->target.raw);
|
||||
free(ops->target.name);
|
||||
}
|
||||
|
||||
static struct ins_ops lock_ops = {
|
||||
.free = lock__delete,
|
||||
.parse = lock__parse,
|
||||
.scnprintf = lock__scnprintf,
|
||||
};
|
||||
|
||||
static int mov__parse(struct ins_operands *ops)
|
||||
{
|
||||
char *s = strchr(ops->raw, ','), *target, *comment, prev;
|
||||
|
||||
if (s == NULL)
|
||||
return -1;
|
||||
|
||||
*s = '\0';
|
||||
ops->source.raw = strdup(ops->raw);
|
||||
*s = ',';
|
||||
|
||||
if (ops->source.raw == NULL)
|
||||
return -1;
|
||||
|
||||
target = ++s;
|
||||
|
||||
while (s[0] != '\0' && !isspace(s[0]))
|
||||
++s;
|
||||
prev = *s;
|
||||
*s = '\0';
|
||||
|
||||
ops->target.raw = strdup(target);
|
||||
*s = prev;
|
||||
|
||||
if (ops->target.raw == NULL)
|
||||
goto out_free_source;
|
||||
|
||||
comment = strchr(s, '#');
|
||||
if (comment == NULL)
|
||||
return 0;
|
||||
|
||||
while (comment[0] != '\0' && isspace(comment[0]))
|
||||
++comment;
|
||||
|
||||
comment__symbol(ops->source.raw, comment, &ops->source.addr, &ops->source.name);
|
||||
comment__symbol(ops->target.raw, comment, &ops->target.addr, &ops->target.name);
|
||||
|
||||
return 0;
|
||||
|
||||
out_free_source:
|
||||
free(ops->source.raw);
|
||||
ops->source.raw = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int mov__scnprintf(struct ins *ins, char *bf, size_t size,
|
||||
struct ins_operands *ops)
|
||||
{
|
||||
return scnprintf(bf, size, "%-6.6s %s,%s", ins->name,
|
||||
ops->source.name ?: ops->source.raw,
|
||||
ops->target.name ?: ops->target.raw);
|
||||
}
|
||||
|
||||
static struct ins_ops mov_ops = {
|
||||
.parse = mov__parse,
|
||||
.scnprintf = mov__scnprintf,
|
||||
};
|
||||
|
||||
static int dec__parse(struct ins_operands *ops)
|
||||
{
|
||||
char *target, *comment, *s, prev;
|
||||
|
||||
target = s = ops->raw;
|
||||
|
||||
while (s[0] != '\0' && !isspace(s[0]))
|
||||
++s;
|
||||
prev = *s;
|
||||
*s = '\0';
|
||||
|
||||
ops->target.raw = strdup(target);
|
||||
*s = prev;
|
||||
|
||||
if (ops->target.raw == NULL)
|
||||
return -1;
|
||||
|
||||
comment = strchr(s, '#');
|
||||
if (comment == NULL)
|
||||
return 0;
|
||||
|
||||
while (comment[0] != '\0' && isspace(comment[0]))
|
||||
++comment;
|
||||
|
||||
comment__symbol(ops->target.raw, comment, &ops->target.addr, &ops->target.name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dec__scnprintf(struct ins *ins, char *bf, size_t size,
|
||||
struct ins_operands *ops)
|
||||
{
|
||||
return scnprintf(bf, size, "%-6.6s %s", ins->name,
|
||||
ops->target.name ?: ops->target.raw);
|
||||
}
|
||||
|
||||
static struct ins_ops dec_ops = {
|
||||
.parse = dec__parse,
|
||||
.scnprintf = dec__scnprintf,
|
||||
};
|
||||
|
||||
static int nop__scnprintf(struct ins *ins __used, char *bf, size_t size,
|
||||
struct ins_operands *ops __used)
|
||||
{
|
||||
@ -127,8 +326,25 @@ static struct ins_ops nop_ops = {
|
||||
* Must be sorted by name!
|
||||
*/
|
||||
static struct ins instructions[] = {
|
||||
{ .name = "add", .ops = &mov_ops, },
|
||||
{ .name = "addl", .ops = &mov_ops, },
|
||||
{ .name = "addq", .ops = &mov_ops, },
|
||||
{ .name = "addw", .ops = &mov_ops, },
|
||||
{ .name = "and", .ops = &mov_ops, },
|
||||
{ .name = "bts", .ops = &mov_ops, },
|
||||
{ .name = "call", .ops = &call_ops, },
|
||||
{ .name = "callq", .ops = &call_ops, },
|
||||
{ .name = "cmp", .ops = &mov_ops, },
|
||||
{ .name = "cmpb", .ops = &mov_ops, },
|
||||
{ .name = "cmpl", .ops = &mov_ops, },
|
||||
{ .name = "cmpq", .ops = &mov_ops, },
|
||||
{ .name = "cmpw", .ops = &mov_ops, },
|
||||
{ .name = "cmpxch", .ops = &mov_ops, },
|
||||
{ .name = "dec", .ops = &dec_ops, },
|
||||
{ .name = "decl", .ops = &dec_ops, },
|
||||
{ .name = "imul", .ops = &mov_ops, },
|
||||
{ .name = "inc", .ops = &dec_ops, },
|
||||
{ .name = "incl", .ops = &dec_ops, },
|
||||
{ .name = "ja", .ops = &jump_ops, },
|
||||
{ .name = "jae", .ops = &jump_ops, },
|
||||
{ .name = "jb", .ops = &jump_ops, },
|
||||
@ -164,9 +380,25 @@ static struct ins instructions[] = {
|
||||
{ .name = "jrcxz", .ops = &jump_ops, },
|
||||
{ .name = "js", .ops = &jump_ops, },
|
||||
{ .name = "jz", .ops = &jump_ops, },
|
||||
{ .name = "lea", .ops = &mov_ops, },
|
||||
{ .name = "lock", .ops = &lock_ops, },
|
||||
{ .name = "mov", .ops = &mov_ops, },
|
||||
{ .name = "movb", .ops = &mov_ops, },
|
||||
{ .name = "movdqa",.ops = &mov_ops, },
|
||||
{ .name = "movl", .ops = &mov_ops, },
|
||||
{ .name = "movq", .ops = &mov_ops, },
|
||||
{ .name = "movslq", .ops = &mov_ops, },
|
||||
{ .name = "movzbl", .ops = &mov_ops, },
|
||||
{ .name = "movzwl", .ops = &mov_ops, },
|
||||
{ .name = "nop", .ops = &nop_ops, },
|
||||
{ .name = "nopl", .ops = &nop_ops, },
|
||||
{ .name = "nopw", .ops = &nop_ops, },
|
||||
{ .name = "or", .ops = &mov_ops, },
|
||||
{ .name = "orl", .ops = &mov_ops, },
|
||||
{ .name = "test", .ops = &mov_ops, },
|
||||
{ .name = "testb", .ops = &mov_ops, },
|
||||
{ .name = "testl", .ops = &mov_ops, },
|
||||
{ .name = "xadd", .ops = &mov_ops, },
|
||||
};
|
||||
|
||||
static int ins__cmp(const void *name, const void *insp)
|
||||
@ -257,6 +489,44 @@ static void disasm_line__init_ins(struct disasm_line *dl)
|
||||
dl->ins->ops->parse(&dl->ops);
|
||||
}
|
||||
|
||||
static int disasm_line__parse(char *line, char **namep, char **rawp)
|
||||
{
|
||||
char *name = line, tmp;
|
||||
|
||||
while (isspace(name[0]))
|
||||
++name;
|
||||
|
||||
if (name[0] == '\0')
|
||||
return -1;
|
||||
|
||||
*rawp = name + 1;
|
||||
|
||||
while ((*rawp)[0] != '\0' && !isspace((*rawp)[0]))
|
||||
++*rawp;
|
||||
|
||||
tmp = (*rawp)[0];
|
||||
(*rawp)[0] = '\0';
|
||||
*namep = strdup(name);
|
||||
|
||||
if (*namep == NULL)
|
||||
goto out_free_name;
|
||||
|
||||
(*rawp)[0] = tmp;
|
||||
|
||||
if ((*rawp)[0] != '\0') {
|
||||
(*rawp)++;
|
||||
while (isspace((*rawp)[0]))
|
||||
++(*rawp);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
out_free_name:
|
||||
free(*namep);
|
||||
*namep = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static struct disasm_line *disasm_line__new(s64 offset, char *line, size_t privsize)
|
||||
{
|
||||
struct disasm_line *dl = zalloc(sizeof(*dl) + privsize);
|
||||
@ -268,35 +538,9 @@ static struct disasm_line *disasm_line__new(s64 offset, char *line, size_t privs
|
||||
goto out_delete;
|
||||
|
||||
if (offset != -1) {
|
||||
char *name = dl->line, tmp;
|
||||
|
||||
while (isspace(name[0]))
|
||||
++name;
|
||||
|
||||
if (name[0] == '\0')
|
||||
goto out_delete;
|
||||
|
||||
dl->ops.raw = name + 1;
|
||||
|
||||
while (dl->ops.raw[0] != '\0' &&
|
||||
!isspace(dl->ops.raw[0]))
|
||||
++dl->ops.raw;
|
||||
|
||||
tmp = dl->ops.raw[0];
|
||||
dl->ops.raw[0] = '\0';
|
||||
dl->name = strdup(name);
|
||||
|
||||
if (dl->name == NULL)
|
||||
if (disasm_line__parse(dl->line, &dl->name, &dl->ops.raw) < 0)
|
||||
goto out_free_line;
|
||||
|
||||
dl->ops.raw[0] = tmp;
|
||||
|
||||
if (dl->ops.raw[0] != '\0') {
|
||||
dl->ops.raw++;
|
||||
while (isspace(dl->ops.raw[0]))
|
||||
++dl->ops.raw;
|
||||
}
|
||||
|
||||
disasm_line__init_ins(dl);
|
||||
}
|
||||
}
|
||||
@ -314,7 +558,10 @@ void disasm_line__free(struct disasm_line *dl)
|
||||
{
|
||||
free(dl->line);
|
||||
free(dl->name);
|
||||
free(dl->ops.target.name);
|
||||
if (dl->ins && dl->ins->ops->free)
|
||||
dl->ins->ops->free(&dl->ops);
|
||||
else
|
||||
ins__delete(&dl->ops);
|
||||
free(dl);
|
||||
}
|
||||
|
||||
|
@ -13,13 +13,26 @@ struct ins;
|
||||
struct ins_operands {
|
||||
char *raw;
|
||||
struct {
|
||||
char *raw;
|
||||
char *name;
|
||||
u64 offset;
|
||||
u64 addr;
|
||||
u64 offset;
|
||||
} target;
|
||||
union {
|
||||
struct {
|
||||
char *raw;
|
||||
char *name;
|
||||
u64 addr;
|
||||
} source;
|
||||
struct {
|
||||
struct ins *ins;
|
||||
struct ins_operands *ops;
|
||||
} locked;
|
||||
};
|
||||
};
|
||||
|
||||
struct ins_ops {
|
||||
void (*free)(struct ins_operands *ops);
|
||||
int (*parse)(struct ins_operands *ops);
|
||||
int (*scnprintf)(struct ins *ins, char *bf, size_t size,
|
||||
struct ins_operands *ops);
|
||||
|
Loading…
Reference in New Issue
Block a user