Latest available version: IDA and decompilers v8.4.240320sp1 see all releases
Hex-Rays logo State-of-the-art binary code analysis tools
email icon
hexrays_sample12.cpp
/*
* Hex-Rays Decompiler project
* Copyright (c) 2007-2024 by Hex-Rays, support@hex-rays.com
* ALL RIGHTS RESERVED.
*
* Sample plugin for Hex-Rays Decompiler.
* It shows a list of direct references to a register from the current
* instruction.
*/
#include <hexrays.hpp>
#include <frame.hpp>
//--------------------------------------------------------------------------
struct plugin_ctx_t : public plugmod_t
{
~plugin_ctx_t()
{
}
virtual bool idaapi run(size_t) override;
};
//--------------------------------------------------------------------------
static void collect_block_xrefs(
eavec_t *out,
mlist_t *list,
const mblock_t *blk,
const minsn_t *ins,
bool find_uses)
{
for ( const minsn_t *p=ins;
p != nullptr && !list->empty();
p = find_uses ? p->next : p->prev )
{
mlist_t use = blk->build_use_list(*p, MUST_ACCESS); // things used by the insn
mlist_t def = blk->build_def_list(*p, MUST_ACCESS); // things defined by the insn
mlist_t &plst = find_uses ? use : def;
if ( list->has_common(plst) )
out->add_unique(p->ea); // this microinstruction seems to use our operand
list->sub(def);
}
}
//--------------------------------------------------------------------------
static void collect_xrefs(
eavec_t *out,
const op_parent_info_t &ctx,
const mop_t *mop,
mlist_t list,
const graph_chains_t &du,
bool find_uses)
{
// first collect the references in the current block
minsn_t *start = find_uses ? ctx.topins->next : ctx.topins->prev;
collect_block_xrefs(out, &list, ctx.blk, start, find_uses);
// then find references in other blocks
int serial = ctx.blk->serial; // block number of the operand
const block_chains_t &bc = du[serial]; // chains of that block
const chain_t *ch = bc.get_chain(*mop); // chain of the operand
if ( ch == nullptr )
return; // odd
for ( int i=0; i < ch->size(); i++ )
{
int bn = ch->at(i);
mblock_t *b = ctx.mba->get_mblock(bn); // block that uses the instruction
minsn_t *ins = find_uses ? b->head : b->tail;
mlist_t tmp = list;
collect_block_xrefs(out, &tmp, b, ins, find_uses);
}
}
//--------------------------------------------------------------------------
static const int xwidths[] = { 3, sizeof(ea_t)*2, 60 };
static const char *const xheader[] = { "Type", "Address", "Instruction" };
struct xref_chooser_t : public chooser_t
{
const eavec_t &xrefs;
const gco_info_t &gco;
ea_t curr_ea;
int ndefs;
xref_chooser_t(
const eavec_t &v,
const char *t,
int n,
ea_t ea,
const gco_info_t &_gco)
: chooser_t(CH_MODAL|CH_KEEP, qnumber(xwidths), xwidths, xheader, t),
xrefs(v), gco(_gco), curr_ea(ea), ndefs(n)
{
}
virtual size_t idaapi get_count() const override { return xrefs.size(); }
virtual void idaapi get_row(
qstrvec_t *cols,
int *,
chooser_item_attrs_t *,
size_t n) const override
{
ea_t ea = get_ea(n);
bool both = (gco.flags & (GCO_USE|GCO_DEF)) == (GCO_USE|GCO_DEF);
cols->at(0) = ea == curr_ea && both ? "use/def"
: n < ndefs ? "def"
: "use";
cols->at(1).sprnt("%a", ea);
generate_disasm_line(&cols->at(2), ea, GENDSM_REMOVE_TAGS);
}
virtual ea_t idaapi get_ea(size_t n) const override
{
return xrefs[n];
}
};
//--------------------------------------------------------------------------
static void show_xrefs(ea_t ea, const gco_info_t &gco, const eavec_t &_xrefs, int ndefs)
{
qstring title;
title.sprnt("xrefs to %s at %a", gco.name.begin(), ea);
xref_chooser_t xc(_xrefs, title.begin(), ndefs, ea, gco);
ssize_t i = xc.choose();
if ( i >= 0 )
jumpto(_xrefs[i]);
}
//--------------------------------------------------------------------------
bool idaapi plugin_ctx_t::run(size_t)
{
ea_t ea = get_screen_ea();
func_t *pfn = get_func(ea);
if ( pfn == nullptr )
{
warning("Please position the cursor within a function");
return true;
}
flags64_t F = get_flags(ea);
if ( !is_code(F) )
{
warning("Please position the cursor on an instruction");
return true;
}
if ( !get_current_operand(&gco) )
{
warning("Could not find a register or stkvar in the current operand");
return true;
}
// generate microcode
mba_ranges_t mbr(pfn);
if ( mba == nullptr )
{
warning("%a: %s", hf.errea, hf.desc().c_str());
return true;
}
merror_t merr = mba->build_graph();
if ( merr != MERR_OK )
{
qstring tmp;
ea_t errea = get_merror_desc(&tmp, merr, mba);
warning("%a: %s", errea, tmp.c_str());
return true;
}
// determine calling conventions without performing any optimizations
// or deleting dead code (doing so would delete an instruction that
// refers to our register and confuse the user)
int ncalls = mba->analyze_calls(ACFL_GUESS);
// we ignore eventual errors and try to show something even if we failed
// to detect some calling conventions
if ( ncalls < 0 )
msg("%a: failed to determine some calling conventions\n", pfn->start_ea);
// prepare mlist for the current operand. we will use to to find references
// to the current operand in the microcode. usually we do not use operands
// (processor instruction operands nor microcode instruction operands)
// for searches. instead, we build a 'mlist_t' instance and use it.
mlist_t list;
if ( !gco.append_to_list(&list, mba) )
{
warning("Failed to represent %s as microcode list", gco.name.c_str());
delete mba;
return false;
}
mop_t *mop = mba->find_mop(&ctx, ea, gco.is_def(), list);
if ( mop == nullptr )
{
warning("Could not find the operand in the microcode, sorry");
delete mba;
return false;
}
eavec_t xrefs;
int ndefs = 0;
{
// get use-def chains. do it inside a block in order to release
// the chains immediately after using them
mbl_graph_t *graph = mba->get_graph();
if ( gco.is_use() )
{
// collect definitions
collect_xrefs(&xrefs, ctx, mop, list, ud, false);
ndefs = xrefs.size();
// register is used by the current instruction - add 'ea' as use-addr
xrefs.add_unique(ea);
}
if ( gco.is_def() )
{
// register is defined by the current instruction - add 'ea' as def-addr
if ( xrefs.add_unique(ea) )
ndefs = xrefs.size();
// collect using
collect_xrefs(&xrefs, ctx, mop, list, du, true);
}
// the chains will be released after quitting the block
}
show_xrefs(ea, gco, xrefs, ndefs);
// We must explicitly delete the microcode array
delete mba;
return true;
}
//--------------------------------------------------------------------------
static plugmod_t *idaapi init()
{
return nullptr; // no decompiler
const char *hxver = get_hexrays_version();
msg("Hex-rays version %s has been detected, %s ready to use\n",
hxver, PLUGIN.wanted_name);
return new plugin_ctx_t;
}
//--------------------------------------------------------------------------
static const char comment[] = "Sample12 plugin for Hex-Rays decompiler";
//--------------------------------------------------------------------------
//
// PLUGIN DESCRIPTION BLOCK
//
//--------------------------------------------------------------------------
plugin_t PLUGIN =
{
IDP_INTERFACE_VERSION,
PLUGIN_MULTI, // The plugin can work with multiple idbs in parallel
init, // initialize
nullptr,
nullptr,
comment, // long comment about the plugin
nullptr, // multiline help about the plugin
"Cross-references to register", // the preferred short name of the plugin
nullptr, // the preferred hotkey to run the plugin
};
Chains of one block.
Definition: hexrays.hpp:3380
const chain_t * get_chain(const voff_t &k, int width=1) const
Get chain for the specified value offset.
Definition: hexrays.hpp:3402
Convenience class to release graph chains automatically.
Definition: hexrays.hpp:5032
ud (use->def) and du (def->use) chain.
Definition: hexrays.hpp:3306
Micro block array (internal representation of the decompiled code).
Definition: hexrays.dox:59
mbl_graph_t * get_graph()
Get control graph.
Definition: hexrays.hpp:11291
merror_t build_graph()
Build control flow graph.
Definition: hexrays.hpp:11285
int analyze_calls(int acflags)
Analyze calls and determine calling conventions.
Definition: hexrays.hpp:11297
const mblock_t * get_mblock(int n) const
Get basic block by its serial number.
Definition: hexrays.hpp:4856
mop_t * find_mop(op_parent_info_t *ctx, ea_t ea, bool is_dest, const mlist_t &list)
Find an operand in the microcode.
Definition: hexrays.hpp:11393
Control flow graph of microcode.
Definition: hexrays.hpp:5063
graph_chains_t * get_ud(gctype_t gctype)
Get use-def chains.
Definition: hexrays.hpp:11475
graph_chains_t * get_du(gctype_t gctype)
Get def-use chains.
Definition: hexrays.hpp:11481
Microcode of one basic block.
Definition: hexrays.hpp:3805
minsn_t * head
pointer to the first instruction of the block
Definition: hexrays.hpp:3840
minsn_t * tail
pointer to the last instruction of the block
Definition: hexrays.hpp:3841
int serial
block number
Definition: hexrays.hpp:3843
mlist_t build_def_list(const minsn_t &ins, maymust_t maymust) const
Build def-list of an instruction.
Definition: hexrays.hpp:11157
mlist_t build_use_list(const minsn_t &ins, maymust_t maymust) const
Build use-list of an instruction.
Definition: hexrays.hpp:11149
Microinstruction class #insn.
Definition: hexrays.hpp:3465
minsn_t * prev
prev insn in doubly linked list. check also previ()
Definition: hexrays.hpp:3472
minsn_t * next
next insn in doubly linked list. check also nexti()
Definition: hexrays.hpp:3471
A microinstruction operand.
Definition: hexrays.hpp:2441
#define DECOMP_WARNINGS
display warnings in the output window
Definition: hexrays.hpp:7142
merror_t
Definition: hexrays.hpp:482
@ MERR_OK
ok
Definition: hexrays.hpp:483
HexRays SDK header file.
#define GCO_USE
is source operand?
Definition: hexrays.hpp:5497
bool init_hexrays_plugin(int flags=0)
Check that your plugin is compatible with hex-rays decompiler.
Definition: hexrays.hpp:8601
ea_t get_merror_desc(qstring *out, merror_t code, mba_t *mba)
Get textual description of an error code.
Definition: hexrays.hpp:9800
bool get_current_operand(gco_info_t *out)
Get the instruction operand under the cursor.
Definition: hexrays.hpp:11567
@ GC_REGS_AND_STKVARS
registers and stkvars (restricted memory only)
Definition: hexrays.hpp:5053
mba_t * gen_microcode(const mba_ranges_t &mbr, hexrays_failure_t *hf=nullptr, const mlist_t *retlist=nullptr, int decomp_flags=0, mba_maturity_t reqmat=MMAT_GLBOPT3)
Generate microcode of an arbitrary code snippet.
Definition: hexrays.hpp:12319
#define ACFL_GUESS
may guess calling conventions
Definition: hexrays.hpp:4804
void term_hexrays_plugin()
Stop working with hex-rays decompiler.
Definition: hexrays.hpp:8609
@ MMAT_PREOPTIMIZED
preoptimized pass is complete
Definition: hexrays.hpp:4338
const char * get_hexrays_version()
Get decompiler version.
Definition: hexrays.hpp:11511
#define GCO_DEF
is destination operand?
Definition: hexrays.hpp:5498
Result of get_current_operand()
Definition: hexrays.hpp:5486
qstring name
register or stkvar name
Definition: hexrays.hpp:5487
bool append_to_list(mlist_t *list, const mba_t *mba) const
Append operand info to LIST.
Definition: hexrays.hpp:11561
int size
operand size
Definition: hexrays.hpp:5493
Exception object: decompiler failure information.
Definition: hexrays.hpp:5442
ea_t errea
associated address
Definition: hexrays.hpp:5444
Ranges to decompile. Either a function or an explicit vector of ranges.
Definition: hexrays.hpp:4362
The context info used by visitors.
Definition: hexrays.hpp:2189