update to ida 7.6, add builds
This commit is contained in:
124
idasdk76/plugins/callee/callee.cpp
Normal file
124
idasdk76/plugins/callee/callee.cpp
Normal file
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Change the callee address for constructions like
|
||||
*
|
||||
* call esi ; LocalFree
|
||||
*
|
||||
*/
|
||||
|
||||
#include <ida.hpp>
|
||||
#include <idp.hpp>
|
||||
#include <loader.hpp>
|
||||
#include <kernwin.hpp>
|
||||
#include <bytes.hpp>
|
||||
#include <auto.hpp>
|
||||
#include <segregs.hpp>
|
||||
#define T 20
|
||||
|
||||
struct callee_vars_t : public plugmod_t
|
||||
{
|
||||
processor_t &ph;
|
||||
callee_vars_t(processor_t &_ph) : ph(_ph) {}
|
||||
virtual bool idaapi run(size_t arg) override;
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static plugmod_t *idaapi init()
|
||||
{
|
||||
processor_t &ph = PH;
|
||||
if ( ph.id != PLFM_386 && ph.id != PLFM_MIPS && ph.id != PLFM_ARM )
|
||||
return nullptr; // only for x86, MIPS and ARM
|
||||
return new callee_vars_t(ph);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static const char comment[] = "Change the callee address";
|
||||
static const char help[] =
|
||||
"This plugin allows the user to change the address of the called function\n"
|
||||
"in constructs like\n"
|
||||
"\n"
|
||||
" call esi\n"
|
||||
"\n"
|
||||
"You can enter a function name instead of its address\n";
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static const char *const form =
|
||||
"HELP\n"
|
||||
"%s\n"
|
||||
"ENDHELP\n"
|
||||
"Enter the callee address\n"
|
||||
"\n"
|
||||
" <~C~allee:$::40:::>\n"
|
||||
"\n"
|
||||
"\n";
|
||||
|
||||
bool idaapi callee_vars_t::run(size_t)
|
||||
{
|
||||
const char *nname;
|
||||
if ( ph.id == PLFM_MIPS )
|
||||
nname = "$ mips";
|
||||
else if ( ph.id == PLFM_ARM )
|
||||
nname = " $arm";
|
||||
else
|
||||
nname = "$ vmm functions";
|
||||
netnode n(nname);
|
||||
ea_t ea = get_screen_ea(); // get current address
|
||||
if ( !is_code(get_flags(ea)) )
|
||||
return false; // not an instruction
|
||||
// get the callee address from the database
|
||||
ea_t callee = node2ea(n.altval_ea(ea)-1);
|
||||
// remove thumb bit for arm
|
||||
if ( ph.id == PLFM_ARM )
|
||||
callee &= ~1;
|
||||
char buf[MAXSTR];
|
||||
qsnprintf(buf, sizeof(buf), form, help);
|
||||
if ( ask_form(buf, &callee) )
|
||||
{
|
||||
if ( callee == BADADDR )
|
||||
{
|
||||
n.altdel_ea(ea);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( ph.id == PLFM_ARM && (callee & 1) == 0 )
|
||||
{
|
||||
// if we're calling a thumb function, set bit 0
|
||||
sel_t tbit = get_sreg(callee, T);
|
||||
if ( tbit != 0 && tbit != BADSEL )
|
||||
callee |= 1;
|
||||
}
|
||||
// save the new address
|
||||
n.altset_ea(ea, ea2node(callee)+1);
|
||||
}
|
||||
gen_idb_event(idb_event::callee_addr_changed, ea, callee);
|
||||
plan_ea(ea); // reanalyze the current instruction
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static const char wanted_name[] = "Change the callee address";
|
||||
static const char wanted_hotkey[] = "Alt-F11";
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// PLUGIN DESCRIPTION BLOCK
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
plugin_t PLUGIN =
|
||||
{
|
||||
IDP_INTERFACE_VERSION,
|
||||
PLUGIN_MULTI, // plugin flags
|
||||
init, // initialize
|
||||
|
||||
nullptr, // terminate. this pointer may be NULL.
|
||||
nullptr, // invoke plugin
|
||||
|
||||
comment, // long comment about the plugin
|
||||
// it could appear in the status line
|
||||
// or as a hint
|
||||
|
||||
help, // multiline help about the plugin
|
||||
|
||||
wanted_name, // the preferred short name of the plugin
|
||||
wanted_hotkey // the preferred hotkey to run the plugin
|
||||
};
|
||||
20
idasdk76/plugins/callee/makefile
Normal file
20
idasdk76/plugins/callee/makefile
Normal file
@@ -0,0 +1,20 @@
|
||||
PROC=callee
|
||||
|
||||
include ../plugin.mak
|
||||
|
||||
# MAKEDEP dependency list ------------------
|
||||
$(F)callee$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
|
||||
$(I)config.hpp $(I)dbg.hpp $(I)fixup.hpp \
|
||||
$(I)fpro.h $(I)funcs.hpp $(I)ida.hpp $(I)idd.hpp \
|
||||
$(I)idp.hpp $(I)ieee.h $(I)kernwin.hpp $(I)lines.hpp \
|
||||
$(I)llong.hpp $(I)loader.hpp \
|
||||
$(I)nalt.hpp $(I)name.hpp \
|
||||
$(I)netnode.hpp $(I)offset.hpp $(I)pro.h \
|
||||
$(I)problems.hpp $(I)range.hpp $(I)segment.hpp \
|
||||
$(I)segregs.hpp $(I)typeinf.hpp $(I)ua.hpp $(I)xref.hpp \
|
||||
\
|
||||
../../module/arm/../idaidp.hpp \
|
||||
\
|
||||
\
|
||||
../../module/arm/arm.hpp \
|
||||
callee.cpp
|
||||
1457
idasdk76/plugins/callgraph/callgraph.cpp
Normal file
1457
idasdk76/plugins/callgraph/callgraph.cpp
Normal file
File diff suppressed because it is too large
Load Diff
332
idasdk76/plugins/callgraph/callgraph.h
Normal file
332
idasdk76/plugins/callgraph/callgraph.h
Normal file
@@ -0,0 +1,332 @@
|
||||
#ifndef __CALLGRAPH__06192009__
|
||||
#define __CALLGRAPH__06192009__
|
||||
|
||||
#include <deque>
|
||||
#include <ida.hpp>
|
||||
#include <idp.hpp>
|
||||
#include <name.hpp>
|
||||
#include <bytes.hpp>
|
||||
#include <graph.hpp>
|
||||
#include <loader.hpp>
|
||||
#include <kernwin.hpp>
|
||||
#include <demangle.hpp>
|
||||
|
||||
#define MAX_CALLERS_LEVEL 10
|
||||
|
||||
#define FIELD_ID_STRINGS 1
|
||||
#define FIELD_ID_LIBS 2
|
||||
#define FIELD_ID_FATHERS 3
|
||||
#define FIELD_ID_CHILDS 4
|
||||
#define FIELD_ID_CHILDS_LEVEL 6
|
||||
|
||||
#define VERTEX_HIDDEN_NODES -1
|
||||
|
||||
struct plugin_ctx_t;
|
||||
typedef std::deque<int> int_queue_t;
|
||||
typedef std::map<ea_t, int> ea_int_map_t;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
struct funcs_walk_options_t
|
||||
{
|
||||
int32 version;
|
||||
#define FWO_VERSION 1 // current version of options block
|
||||
int32 flags;
|
||||
#define FWO_SHOWSTRING 0x0001 // show string references
|
||||
#define FWO_SKIPLIB 0x0002 // skip library functions
|
||||
#define FWO_CALLEE_RECURSE_UNLIM 0x0004 // unlimited callees recursion
|
||||
int32 callees_recurse_limit; // how deep to recurse callees (0 = unlimited)
|
||||
int32 callers_recurse_limit; // how deep to recurse callers (0 = unlimited)
|
||||
int32 max_nodes; // maximum number of nodes per level
|
||||
};
|
||||
|
||||
class graph_info_t;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// function call graph creator class
|
||||
class callgraph_t
|
||||
{
|
||||
public:
|
||||
plugin_ctx_t &ctx;
|
||||
|
||||
private:
|
||||
int node_count = 0;
|
||||
|
||||
// node id to func addr and reverse lookup
|
||||
typedef std::map<int, ea_t> int_ea_map_t;
|
||||
int_ea_map_t node2ea;
|
||||
|
||||
// current node search ptr
|
||||
int cur_node = 0;
|
||||
char cur_text[MAXSTR];
|
||||
|
||||
bool visited(ea_t func_ea, int *nid);
|
||||
int add(ea_t func_ea);
|
||||
|
||||
public:
|
||||
|
||||
ea_int_map_t ea2node;
|
||||
// edge structure
|
||||
struct edge_t
|
||||
{
|
||||
int id1;
|
||||
int id2;
|
||||
edge_t(int i1, int i2): id1(i1), id2(i2) {}
|
||||
edge_t(): id1(0), id2(0) {}
|
||||
};
|
||||
typedef qlist<edge_t> edges_t;
|
||||
|
||||
// edge manipulation
|
||||
typedef edges_t::iterator edge_iterator;
|
||||
void create_edge(int id1, int id2);
|
||||
edge_iterator begin_edges() { return edges.begin(); }
|
||||
edge_iterator end_edges() { return edges.end(); }
|
||||
void clear_edges();
|
||||
|
||||
// find nodes by text
|
||||
int find_first(const char *text);
|
||||
int find_next();
|
||||
const char *get_findtext() { return cur_text; }
|
||||
callgraph_t(plugin_ctx_t &ctx);
|
||||
int count() const { return node_count; }
|
||||
void reset();
|
||||
|
||||
// node / func info
|
||||
struct funcinfo_t
|
||||
{
|
||||
qstring name;
|
||||
bgcolor_t color;
|
||||
ea_t ea;
|
||||
qstring strings;
|
||||
};
|
||||
typedef std::map<int, funcinfo_t> int_funcinfo_map_t;
|
||||
int_funcinfo_map_t cached_funcs;
|
||||
funcinfo_t *get_info(int nid);
|
||||
|
||||
// function name manipulation
|
||||
ea_t get_addr(int nid) const;
|
||||
const char *get_name(int nid);
|
||||
|
||||
int walk_func(eavec_t *hide_nodes, func_t *func, funcs_walk_options_t *o=NULL, int level=1);
|
||||
void add_fathers(func_t *func, ea_t func_start, int id, funcs_walk_options_t *opt, int level);
|
||||
|
||||
bool navigate(graph_info_t *gi, ea_t addr) const;
|
||||
|
||||
void go_back(graph_info_t *gi) const;
|
||||
void go_forward(graph_info_t *gi) const;
|
||||
|
||||
bool options(graph_info_t *gi) const;
|
||||
bool refresh(graph_info_t *gi) const;
|
||||
|
||||
bool jumpxref(graph_info_t *gi) const;
|
||||
bool jumpaddr(graph_info_t *gi) const;
|
||||
bool jump(const graph_info_t *gi) const;
|
||||
bool back(graph_info_t *gi) const;
|
||||
bool forward(graph_info_t *gi) const;
|
||||
|
||||
bool center(graph_info_t *gi) const;
|
||||
bool select(const graph_info_t *gi) const;
|
||||
bool home(const graph_info_t *gi) const;
|
||||
bool searchfirst(graph_info_t *gi);
|
||||
bool searchnext(graph_info_t *gi);
|
||||
bool hidenode(graph_info_t *gi) const;
|
||||
bool showhidden(graph_info_t *gi) const;
|
||||
bool showall(graph_info_t *gi) const;
|
||||
|
||||
static ssize_t idaapi gr_callback(void *ud, int code, va_list va);
|
||||
static void idaapi user_refresh(void *ud, int code, va_list va, int current_node);
|
||||
private:
|
||||
edges_t edges;
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
DECLARE_LISTENER(view_listener_t, plugin_ctx_t, ctx);
|
||||
DECLARE_LISTENER(idp_gi_listener_t, graph_info_t, gi);
|
||||
DECLARE_LISTENER(idb_gi_listener_t, graph_info_t, gi);
|
||||
|
||||
struct idp_merge_listener_t : public event_listener_t
|
||||
{
|
||||
virtual ssize_t idaapi on_event(ssize_t code, va_list va) override;
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Per function call graph context
|
||||
typedef qlist<class graph_info_t *> graphinfo_list_t;
|
||||
class graph_info_t
|
||||
{
|
||||
plugin_ctx_t &ctx;
|
||||
idp_gi_listener_t idp_gi_listener = idp_gi_listener_t(*this);
|
||||
idb_gi_listener_t idb_gi_listener = idb_gi_listener_t(*this);
|
||||
|
||||
public:
|
||||
typedef graphinfo_list_t::iterator iterator;
|
||||
|
||||
callgraph_t fg; // associated call graph maker
|
||||
graph_viewer_t *gv = nullptr; // associated graph_view
|
||||
TWidget *widget = nullptr; // associated widget
|
||||
ea_t func_ea = BADADDR; // function ea in question
|
||||
qstring title; // the title
|
||||
|
||||
int_queue_t queue;
|
||||
int_queue_t forward_queue;
|
||||
|
||||
eavec_t hide_nodes;
|
||||
|
||||
private:
|
||||
bool refresh_needed = true; // schedule a refresh
|
||||
|
||||
graph_info_t(plugin_ctx_t &_ctx) : ctx(_ctx), fg(_ctx) {}
|
||||
static bool find(plugin_ctx_t &ctx, ea_t func_ea, iterator *out);
|
||||
public:
|
||||
static graph_info_t *find(plugin_ctx_t &ctx, ea_t func_ea);
|
||||
static graph_info_t *find(plugin_ctx_t &ctx, const char *title);
|
||||
static graph_info_t *find(plugin_ctx_t &ctx, const graph_viewer_t *v);
|
||||
static graph_info_t *create(plugin_ctx_t &ctx, ea_t func_ea);
|
||||
static void destroy_graph(plugin_ctx_t &ctx, graph_info_t *gi);
|
||||
void install_hooks();
|
||||
void remove_hooks();
|
||||
void mark_for_refresh(void);
|
||||
void mark_as_refreshed(void);
|
||||
void refresh(void);
|
||||
bool is_refresh_needed(void) const { return refresh_needed; }
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// The main action to invoke the plugin
|
||||
struct show_callgraph_ah_t : public action_handler_t
|
||||
{
|
||||
plugin_ctx_t &ctx;
|
||||
show_callgraph_ah_t(plugin_ctx_t &_ctx) : ctx(_ctx) {}
|
||||
virtual int idaapi activate(action_activation_ctx_t *) override;
|
||||
virtual action_state_t idaapi update(action_update_ctx_t *) override
|
||||
{
|
||||
return AST_ENABLE_ALWAYS;
|
||||
}
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Base class for additional actions in the graph view
|
||||
struct cg_ah_t : public action_handler_t
|
||||
{
|
||||
plugin_ctx_t &plg;
|
||||
cg_ah_t(plugin_ctx_t &p) : plg(p) {}
|
||||
virtual int act(graph_info_t *gi) = 0;
|
||||
|
||||
virtual int idaapi activate(action_activation_ctx_t *ctx) override
|
||||
{
|
||||
graph_info_t *gi = graph_info_t::find(plg, (graph_viewer_t *) ctx->widget);
|
||||
return gi != nullptr ? act(gi) : 0;
|
||||
}
|
||||
|
||||
virtual action_state_t idaapi update(action_update_ctx_t *ctx) override
|
||||
{
|
||||
return graph_info_t::find(plg, (graph_viewer_t *) ctx->widget) != nullptr
|
||||
? AST_ENABLE_FOR_WIDGET
|
||||
: AST_DISABLE_FOR_WIDGET;
|
||||
}
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
#define DECLARE_ACTION_HANDLER(Method) \
|
||||
struct Method##_ah_t : public cg_ah_t \
|
||||
{ \
|
||||
Method##_ah_t(plugin_ctx_t &p) : cg_ah_t(p) {} \
|
||||
virtual int act(graph_info_t *gi) override \
|
||||
{ \
|
||||
return int(gi->fg.Method(gi)); \
|
||||
} \
|
||||
}
|
||||
DECLARE_ACTION_HANDLER(options);
|
||||
DECLARE_ACTION_HANDLER(refresh);
|
||||
DECLARE_ACTION_HANDLER(jumpxref);
|
||||
DECLARE_ACTION_HANDLER(jumpaddr);
|
||||
DECLARE_ACTION_HANDLER(jump);
|
||||
DECLARE_ACTION_HANDLER(back);
|
||||
DECLARE_ACTION_HANDLER(forward);
|
||||
DECLARE_ACTION_HANDLER(center);
|
||||
DECLARE_ACTION_HANDLER(select);
|
||||
DECLARE_ACTION_HANDLER(home);
|
||||
DECLARE_ACTION_HANDLER(searchfirst);
|
||||
DECLARE_ACTION_HANDLER(searchnext);
|
||||
DECLARE_ACTION_HANDLER(hidenode);
|
||||
DECLARE_ACTION_HANDLER(showhidden);
|
||||
DECLARE_ACTION_HANDLER(showall);
|
||||
#undef DECLARE_ACTION_HANDLER
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
#define PROCMOD_NODE_NAME "$ proximity browser"
|
||||
|
||||
struct plugin_ctx_t : public plugmod_t
|
||||
{
|
||||
view_listener_t view_listener = view_listener_t(*this);
|
||||
idp_merge_listener_t idp_merge_listener;
|
||||
|
||||
show_callgraph_ah_t show_callgraph_ah = show_callgraph_ah_t(*this);
|
||||
const action_desc_t main_action;
|
||||
#define DEFINE_ACTION_HANDLER(Method) Method##_ah_t Method##_ah = Method##_ah_t(*this) //lint !e773 macro not parenthized
|
||||
DEFINE_ACTION_HANDLER(options);
|
||||
DEFINE_ACTION_HANDLER(refresh);
|
||||
DEFINE_ACTION_HANDLER(jumpxref);
|
||||
DEFINE_ACTION_HANDLER(jumpaddr);
|
||||
DEFINE_ACTION_HANDLER(jump);
|
||||
DEFINE_ACTION_HANDLER(back);
|
||||
DEFINE_ACTION_HANDLER(forward);
|
||||
DEFINE_ACTION_HANDLER(center);
|
||||
DEFINE_ACTION_HANDLER(select);
|
||||
DEFINE_ACTION_HANDLER(home);
|
||||
DEFINE_ACTION_HANDLER(searchfirst);
|
||||
DEFINE_ACTION_HANDLER(searchnext);
|
||||
DEFINE_ACTION_HANDLER(hidenode);
|
||||
DEFINE_ACTION_HANDLER(showhidden);
|
||||
DEFINE_ACTION_HANDLER(showall);
|
||||
#undef DEFINE_ACTION_HANDLER
|
||||
const action_desc_t actions[15] =
|
||||
{
|
||||
#define ROW(Method, Label, Shortcut) \
|
||||
ACTION_DESC_LITERAL_PLUGMOD("callgraph:" #Method, Label, &Method##_ah, this, Shortcut, nullptr, -1)
|
||||
ROW(options, "Options", "O"), // 1
|
||||
ROW(refresh, "Refresh", "R"), // 2
|
||||
ROW(jumpxref, "Jump to xref", "X"), // 3
|
||||
ROW(jumpaddr, "Jump to address", "G"), // 4
|
||||
ROW(jump, "Jump to function", "SPACE"), // 5
|
||||
ROW(back, "Jump to previous node", "ESC"), // 6
|
||||
ROW(forward, "Jump to next node", "Ctrl+Enter"), // 7
|
||||
ROW(center, "Center node", "Enter"), // 8
|
||||
ROW(select, "Select node", "Ctrl+L"), // 9
|
||||
ROW(home, "Goto to first node", "H"), // 0
|
||||
ROW(searchfirst, "Search first", "S"), // 1
|
||||
ROW(searchnext, "Search next", "N"), // 2
|
||||
ROW(hidenode, "Hide selected node", nullptr), // 3
|
||||
ROW(showhidden, "Show hidden node", nullptr), // 4
|
||||
ROW(showall, "Show all nodes", nullptr), // 5
|
||||
#undef ROW
|
||||
};
|
||||
|
||||
graphinfo_list_t instances;
|
||||
funcs_walk_options_t fg_opts =
|
||||
{
|
||||
FWO_VERSION, // version
|
||||
FWO_CALLEE_RECURSE_UNLIM, // flags
|
||||
2, // max callees recursion
|
||||
1, // max callers recursion
|
||||
255 // max nodes per level
|
||||
};
|
||||
|
||||
bool actions_registered = false;
|
||||
|
||||
qstring last_text; //lint !e958 padding // see findfirst_node()
|
||||
|
||||
|
||||
virtual bool idaapi run(size_t arg) override;
|
||||
plugin_ctx_t();
|
||||
bool register_main_action();
|
||||
~plugin_ctx_t();
|
||||
qstring gen_graph_title(ea_t ea);
|
||||
bool load_options();
|
||||
void save_options();
|
||||
bool show_options();
|
||||
void ensure_actions_registered();
|
||||
};
|
||||
|
||||
extern int data_id;
|
||||
|
||||
#endif
|
||||
15
idasdk76/plugins/callgraph/makefile
Normal file
15
idasdk76/plugins/callgraph/makefile
Normal file
@@ -0,0 +1,15 @@
|
||||
PROC=callgraph
|
||||
|
||||
|
||||
include ../plugin.mak
|
||||
|
||||
# MAKEDEP dependency list ------------------
|
||||
$(F)callgraph$(O): $(I)bitrange.hpp $(I)bytes.hpp $(I)config.hpp \
|
||||
$(I)demangle.hpp $(I)fpro.h $(I)funcs.hpp \
|
||||
$(I)gdl.hpp $(I)graph.hpp $(I)ida.hpp $(I)idp.hpp \
|
||||
$(I)ieee.h $(I)kernwin.hpp $(I)lines.hpp $(I)llong.hpp \
|
||||
$(I)loader.hpp \
|
||||
$(I)nalt.hpp $(I)name.hpp $(I)netnode.hpp $(I)pro.h \
|
||||
$(I)range.hpp $(I)segment.hpp $(I)ua.hpp $(I)xref.hpp \
|
||||
callgraph.cpp callgraph.h
|
||||
|
||||
189
idasdk76/plugins/choose/choose.cpp
Normal file
189
idasdk76/plugins/choose/choose.cpp
Normal file
@@ -0,0 +1,189 @@
|
||||
/*
|
||||
* This is a sample plugin module
|
||||
*
|
||||
* It demonstrates the use of the choose() function
|
||||
*
|
||||
*/
|
||||
|
||||
#include <ida.hpp>
|
||||
#include <idp.hpp>
|
||||
#include <loader.hpp>
|
||||
#include <bytes.hpp>
|
||||
#include <kernwin.hpp>
|
||||
|
||||
struct plugin_ctx_t : public plugmod_t
|
||||
{
|
||||
virtual bool idaapi run(size_t arg) override;
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static plugmod_t *idaapi init()
|
||||
{
|
||||
return new plugin_ctx_t;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// non-modal call instruction chooser
|
||||
struct calls_chooser_t : public chooser_t
|
||||
{
|
||||
protected:
|
||||
static const int widths_[];
|
||||
static const char *const header_[];
|
||||
|
||||
public:
|
||||
// remember the call instruction addresses in this qvector
|
||||
eavec_t list;
|
||||
|
||||
// this object must be allocated using `new`
|
||||
calls_chooser_t(const char *title, bool ok, func_item_iterator_t *fii);
|
||||
|
||||
// function that is used to decide whether a new chooser should be opened
|
||||
// or we can use the existing one.
|
||||
// The contents of the window are completely determined by its title
|
||||
virtual const void *get_obj_id(size_t *len) const override
|
||||
{
|
||||
*len = strlen(title);
|
||||
return title;
|
||||
}
|
||||
|
||||
// function that returns number of lines in the list
|
||||
virtual size_t idaapi get_count() const override { return list.size(); }
|
||||
|
||||
// function that generates the list line
|
||||
virtual void idaapi get_row(
|
||||
qstrvec_t *cols,
|
||||
int *icon_,
|
||||
chooser_item_attrs_t *attrs,
|
||||
size_t n) const override;
|
||||
|
||||
// function that is called when the user hits Enter
|
||||
virtual cbret_t idaapi enter(size_t n) override
|
||||
{
|
||||
if ( n < list.size() )
|
||||
jumpto(list[n]);
|
||||
return cbret_t(); // nothing changed
|
||||
}
|
||||
|
||||
protected:
|
||||
void build_list(bool ok, func_item_iterator_t *fii)
|
||||
{
|
||||
insn_t insn;
|
||||
while ( ok )
|
||||
{
|
||||
ea_t ea = fii->current();
|
||||
if ( decode_insn(&insn, ea) > 0 && is_call_insn(insn) ) // a call instruction is found
|
||||
list.push_back(ea);
|
||||
ok = fii->next_code();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// column widths
|
||||
const int calls_chooser_t::widths_[] =
|
||||
{
|
||||
CHCOL_HEX | 8, // Address
|
||||
32, // Instruction
|
||||
};
|
||||
// column headers
|
||||
const char *const calls_chooser_t::header_[] =
|
||||
{
|
||||
"Address", // 0
|
||||
"Instruction", // 1
|
||||
};
|
||||
|
||||
inline calls_chooser_t::calls_chooser_t(
|
||||
const char *title_,
|
||||
bool ok,
|
||||
func_item_iterator_t *fii)
|
||||
: chooser_t(0, qnumber(widths_), widths_, header_, title_),
|
||||
list()
|
||||
{
|
||||
CASSERT(qnumber(widths_) == qnumber(header_));
|
||||
|
||||
// build the list of calls
|
||||
build_list(ok, fii);
|
||||
}
|
||||
|
||||
void idaapi calls_chooser_t::get_row(
|
||||
qstrvec_t *cols_,
|
||||
int *,
|
||||
chooser_item_attrs_t *,
|
||||
size_t n) const
|
||||
{
|
||||
// assert: n < list.size()
|
||||
ea_t ea = list[n];
|
||||
|
||||
// generate the line
|
||||
qstrvec_t &cols = *cols_;
|
||||
cols[0].sprnt("%08a", ea);
|
||||
generate_disasm_line(&cols[1], ea, GENDSM_REMOVE_TAGS);
|
||||
CASSERT(qnumber(header_) == 2);
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// The plugin method
|
||||
// This is the main function of the plugin.
|
||||
bool idaapi plugin_ctx_t::run(size_t)
|
||||
{
|
||||
qstring title;
|
||||
// Let's display the functions called from the current one
|
||||
// or from the selected area
|
||||
|
||||
// First we determine the working area
|
||||
func_item_iterator_t fii;
|
||||
bool ok;
|
||||
ea_t ea1, ea2;
|
||||
if ( read_range_selection(NULL, &ea1, &ea2) ) // the selection is present?
|
||||
{
|
||||
callui(ui_unmarksel); // unmark selection
|
||||
title.sprnt("Functions called from %08a..%08a", ea1, ea2);
|
||||
ok = fii.set_range(ea1, ea2);
|
||||
}
|
||||
else // nothing is selected
|
||||
{
|
||||
func_t *pfn = get_func(get_screen_ea()); // try the current function
|
||||
if ( pfn == NULL )
|
||||
{
|
||||
warning("Please position the cursor on a function or select an area");
|
||||
return true;
|
||||
}
|
||||
ok = fii.set(pfn);
|
||||
get_func_name(&title, pfn->start_ea);
|
||||
title.insert("Functions called from ");
|
||||
}
|
||||
|
||||
// now open the window
|
||||
calls_chooser_t *ch = new calls_chooser_t(title.c_str(), ok, &fii);
|
||||
ch->choose(); // the default cursor position is 0 (first row)
|
||||
return true; //-V773
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// PLUGIN DESCRIPTION BLOCK
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
plugin_t PLUGIN =
|
||||
{
|
||||
IDP_INTERFACE_VERSION,
|
||||
// plugin flags
|
||||
PLUGIN_MULTI,
|
||||
// initialize
|
||||
init,
|
||||
nullptr,
|
||||
nullptr,
|
||||
// long comment about the plugin
|
||||
// it could appear in the status line
|
||||
// or as a hint
|
||||
"This is a sample plugin. It displays the chooser window",
|
||||
// multiline help about the plugin
|
||||
"A sample plugin module\n"
|
||||
"\n"
|
||||
"This module shows you how to use choose() function.\n",
|
||||
|
||||
// the preferred short name of the plugin
|
||||
"Called functions",
|
||||
// the preferred hotkey to run the plugin
|
||||
""
|
||||
};
|
||||
11
idasdk76/plugins/choose/makefile
Normal file
11
idasdk76/plugins/choose/makefile
Normal file
@@ -0,0 +1,11 @@
|
||||
PROC=choose
|
||||
|
||||
include ../plugin.mak
|
||||
|
||||
# MAKEDEP dependency list ------------------
|
||||
$(F)choose$(O) : $(I)bitrange.hpp $(I)bytes.hpp $(I)config.hpp $(I)fpro.h \
|
||||
$(I)funcs.hpp $(I)ida.hpp $(I)idp.hpp $(I)ieee.h \
|
||||
$(I)kernwin.hpp $(I)lines.hpp $(I)llong.hpp \
|
||||
$(I)loader.hpp $(I)nalt.hpp $(I)netnode.hpp $(I)pro.h \
|
||||
$(I)range.hpp $(I)segment.hpp $(I)ua.hpp $(I)xref.hpp \
|
||||
choose.cpp
|
||||
177
idasdk76/plugins/custdata/custdata.cpp
Normal file
177
idasdk76/plugins/custdata/custdata.cpp
Normal file
@@ -0,0 +1,177 @@
|
||||
/* Custom data type sample plugin.
|
||||
* Copyright (c) 2010-2021 Hex-Rays, support@hex-rays.com
|
||||
* Feel free to do whatever you want with this code.
|
||||
*
|
||||
* This sample plugin demonstates how to install a custom data type
|
||||
* and a custom data format in IDA v5.7
|
||||
*
|
||||
* Custom data types can be used to create your own data types.
|
||||
* A custom data type basically defines the data size. It can be fixed
|
||||
* or variable. This plugin defines a variable size data type: a pascal
|
||||
* string. Pascal strings start with a count byte:
|
||||
* db len, '....'
|
||||
*
|
||||
* Custom data formats are used to render data values on the screen.
|
||||
* Multiple data formats can be registered for a custom data type.
|
||||
* The data formats with non-NULL menu_names will be listed in the 'Operand type'
|
||||
* menu and the user will be able to select them.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <ida.hpp>
|
||||
#include <idp.hpp>
|
||||
#include <struct.hpp>
|
||||
#include <loader.hpp>
|
||||
#include <kernwin.hpp>
|
||||
|
||||
struct plugin_ctx_t : public plugmod_t
|
||||
{
|
||||
int psid = 0; // id of the 'pascal string' data type
|
||||
int psfid = 0; // id of the 'pascal string' data format
|
||||
|
||||
plugin_ctx_t();
|
||||
~plugin_ctx_t();
|
||||
virtual bool idaapi run(size_t) override { return false; }
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// We define a variable size data type. For fixed size types this function
|
||||
// must be omitted.
|
||||
static asize_t idaapi calc_pascal_string_length(void *, ea_t ea, asize_t maxsize)
|
||||
{
|
||||
if ( is_member_id(ea) )
|
||||
{ // Custom data types may be used in structure definitions. If this case
|
||||
// ea is a member id. Check for this situation and return 1
|
||||
return 1;
|
||||
}
|
||||
ushort n = get_byte(ea);
|
||||
if ( n+1 > maxsize )
|
||||
return 0; // string would be too big
|
||||
return n+1; // ok, we accept any pascal string
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Definition of the data type
|
||||
static const data_type_t pascal_string_type =
|
||||
{
|
||||
sizeof(data_type_t), // size of this structure
|
||||
NULL, // user defined data
|
||||
0, // properties
|
||||
"pascal_string", // internal name of the data type
|
||||
// must be unique for the current database
|
||||
"Pascal string", // Menu name. If NULL, the type won't be visible in the Edit menu.
|
||||
NULL, // Hotkey
|
||||
"pstr", // Keyword to use in the assembly listing
|
||||
2, // value size. For varsize types, specify the
|
||||
// minimal size of the value
|
||||
NULL, // may_create_at? NULL means the type can be created anywhere
|
||||
calc_pascal_string_length, // for varsize types: calculate the exact size of an item
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Print contents of a pascal string
|
||||
static bool idaapi print_pascal_string(
|
||||
void *, // user defined data, not used here
|
||||
qstring *out, // output buffer. may be NULL
|
||||
const void *value, // value to print. may not be NULL
|
||||
asize_t size, // value size in bytes
|
||||
ea_t, // current ea
|
||||
int, // operand number
|
||||
int) // data type id
|
||||
{
|
||||
const char *vptr = (const char *)value;
|
||||
int n = *vptr++;
|
||||
if ( n+1 > size )
|
||||
return false;
|
||||
|
||||
if ( out != NULL )
|
||||
{
|
||||
*out = "\"";
|
||||
for ( int i=0; i < n; i++ )
|
||||
{
|
||||
if ( qisprint(*vptr) )
|
||||
out->append(*vptr++);
|
||||
else
|
||||
out->cat_sprnt("\\x%02X", uchar(*vptr++));
|
||||
}
|
||||
out->append('"');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Definition of the data format
|
||||
static const data_format_t pascal_string_format =
|
||||
{
|
||||
sizeof(data_format_t), // size of this structure
|
||||
NULL, // user defined data
|
||||
0, // properties
|
||||
"pascal_string", // internal name of the data format
|
||||
NULL, // Menu name of the format. NULL means 'do not create menu item'
|
||||
NULL, // Hotkey
|
||||
0, // value size. 0 means that this format accepts any value size
|
||||
0, // Text width of the value. Unknown, specify 0
|
||||
print_pascal_string, // callback to render colored text for the data
|
||||
NULL, // scan
|
||||
NULL, // analyze
|
||||
};
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static plugmod_t *idaapi init()
|
||||
{
|
||||
processor_t &ph = PH;
|
||||
if ( ph.id != PLFM_386 )
|
||||
return nullptr;
|
||||
return new plugin_ctx_t;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
plugin_ctx_t::plugin_ctx_t()
|
||||
{
|
||||
// Register custom data type
|
||||
psid = register_custom_data_type(&pascal_string_type);
|
||||
// Register custom data format for it
|
||||
psfid = register_custom_data_format(&pascal_string_format);
|
||||
attach_custom_data_format(psid, psfid);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
plugin_ctx_t::~plugin_ctx_t()
|
||||
{
|
||||
// unregister data type
|
||||
if ( psid > 0 )
|
||||
{
|
||||
// IDA would detach the data format automatically.
|
||||
unregister_custom_data_type(psid);
|
||||
}
|
||||
// unregister data format
|
||||
if ( psfid > 0 )
|
||||
unregister_custom_data_format(psfid);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// PLUGIN DESCRIPTION BLOCK
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
plugin_t PLUGIN =
|
||||
{
|
||||
IDP_INTERFACE_VERSION,
|
||||
PLUGIN_PROC // plugin flags
|
||||
// we want the plugin to load as soon as possible
|
||||
// immediately after the processor module
|
||||
|PLUGIN_HIDE // we want to hide the plugin because it there will
|
||||
// be a menu item in the Edit submenu
|
||||
|PLUGIN_MULTI, // this plugin can work with multiple idbs in parallel
|
||||
init, // initialize
|
||||
nullptr,
|
||||
nullptr,
|
||||
"", // long comment about the plugin
|
||||
// it could appear in the status line
|
||||
// or as a hint
|
||||
"", // multiline help about the plugin
|
||||
|
||||
"Sample custdata", // the preferred short name of the plugin
|
||||
"" // the preferred hotkey to run the plugin
|
||||
};
|
||||
11
idasdk76/plugins/custdata/makefile
Normal file
11
idasdk76/plugins/custdata/makefile
Normal file
@@ -0,0 +1,11 @@
|
||||
PROC=custdata
|
||||
|
||||
include ../plugin.mak
|
||||
|
||||
# MAKEDEP dependency list ------------------
|
||||
$(F)custdata$(O): $(I)bitrange.hpp $(I)bytes.hpp $(I)config.hpp $(I)fpro.h \
|
||||
$(I)funcs.hpp $(I)ida.hpp $(I)idp.hpp $(I)ieee.h \
|
||||
$(I)kernwin.hpp $(I)lines.hpp $(I)llong.hpp \
|
||||
$(I)loader.hpp $(I)nalt.hpp $(I)netnode.hpp $(I)pro.h \
|
||||
$(I)range.hpp $(I)segment.hpp $(I)struct.hpp $(I)ua.hpp \
|
||||
$(I)xref.hpp custdata.cpp
|
||||
282
idasdk76/plugins/custview/custview.cpp
Normal file
282
idasdk76/plugins/custview/custview.cpp
Normal file
@@ -0,0 +1,282 @@
|
||||
/* Custom viewer sample plugin.
|
||||
* Copyright (c) 2007 by Ilfak Guilfanov, ig@hexblog.com
|
||||
* Feel free to do whatever you want with this code.
|
||||
*
|
||||
* This sample plugin demonstates how to create and manipulate a simple
|
||||
* custom viewer in IDA v5.1
|
||||
*
|
||||
* Custom viewers allow you to create a view which displays colored lines.
|
||||
* These colored lines are dynamically created by callback functions.
|
||||
*
|
||||
* Custom viewers are used in IDA itself to display
|
||||
* the disassembly listng, structure, and enumeration windows.
|
||||
*
|
||||
* This sample plugin just displays several sample lines on the screen.
|
||||
* It displays a hint with the current line number.
|
||||
* The right-click menu contains one sample command.
|
||||
* It reacts to one hotkey.
|
||||
*
|
||||
* This plugin uses the simpleline_place_t class for the locations.
|
||||
* Custom viewers can use any decendant of the place_t class.
|
||||
* The place_t is responsible for supplying data to the viewer.
|
||||
*/
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
#include <ida.hpp>
|
||||
#include <idp.hpp>
|
||||
#include <loader.hpp>
|
||||
#include <kernwin.hpp>
|
||||
|
||||
#define ACTION_NAME "custview:SampleMenuItem"
|
||||
|
||||
struct plugin_ctx_t;
|
||||
struct sample_action_t : public action_handler_t
|
||||
{
|
||||
plugin_ctx_t &plg;
|
||||
sample_action_t(plugin_ctx_t &p) : plg(p) {}
|
||||
virtual int idaapi activate(action_activation_ctx_t *) override;
|
||||
virtual action_state_t idaapi update(action_update_ctx_t *) override
|
||||
{
|
||||
return AST_ENABLE_ALWAYS;
|
||||
}
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
static struct
|
||||
{
|
||||
const char *text;
|
||||
bgcolor_t color;
|
||||
} const sample_text[] =
|
||||
{
|
||||
{ "This is a sample text", 0xFFFFFF },
|
||||
{ "It will be displayed in the custom view", 0xFFC0C0 },
|
||||
{ COLSTR("This line will be colored as erroneous", SCOLOR_ERROR), 0xC0FFC0 },
|
||||
{ COLSTR("Every", SCOLOR_AUTOCMT) " "
|
||||
COLSTR("word", SCOLOR_DNAME) " "
|
||||
COLSTR("can", SCOLOR_IMPNAME) " "
|
||||
COLSTR("be", SCOLOR_NUMBER) " "
|
||||
COLSTR("colored!", SCOLOR_EXTRA), 0xC0C0FF },
|
||||
{ " No limit on the number of lines.", 0xC0FFFF },
|
||||
};
|
||||
|
||||
// Structure to keep all information about the our sample view
|
||||
struct sample_info_t
|
||||
{
|
||||
TWidget *cv;
|
||||
strvec_t sv;
|
||||
sample_info_t() : cv(NULL) {}
|
||||
};
|
||||
|
||||
struct plugin_ctx_t : public plugmod_t, public event_listener_t
|
||||
{
|
||||
sample_info_t *si = NULL;
|
||||
const sample_info_t *last_si = NULL;
|
||||
|
||||
sample_action_t sample_ah = sample_action_t(*this);
|
||||
const action_desc_t sample_action = ACTION_DESC_LITERAL_PLUGMOD(
|
||||
ACTION_NAME,
|
||||
"Sample menu item",
|
||||
&sample_ah,
|
||||
this,
|
||||
"N",
|
||||
NULL,
|
||||
-1);
|
||||
|
||||
virtual bool idaapi run(size_t) override;
|
||||
virtual ssize_t idaapi on_event(ssize_t code, va_list va) override;
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// get the word under the (keyboard or mouse) cursor
|
||||
static bool get_current_word(TWidget *v, bool mouse, qstring &word)
|
||||
{
|
||||
// query the cursor position
|
||||
int x, y;
|
||||
if ( get_custom_viewer_place(v, mouse, &x, &y) == NULL )
|
||||
return false;
|
||||
|
||||
// query the line at the cursor
|
||||
qstring buf;
|
||||
tag_remove(&buf, get_custom_viewer_curline(v, mouse));
|
||||
if ( x >= buf.length() )
|
||||
return false;
|
||||
|
||||
// find the beginning of the word
|
||||
char *ptr = buf.begin() + x;
|
||||
while ( ptr > buf.begin() && !qisspace(ptr[-1]) )
|
||||
ptr--;
|
||||
|
||||
// find the end of the word
|
||||
char *begin = ptr;
|
||||
ptr = buf.begin() + x;
|
||||
while ( !qisspace(*ptr) && *ptr != '\0' )
|
||||
ptr++;
|
||||
|
||||
word = qstring(begin, ptr-begin);
|
||||
return true;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
int idaapi sample_action_t::activate(action_activation_ctx_t *)
|
||||
{
|
||||
qstring word;
|
||||
if ( !get_current_word(plg.last_si->cv, false, word) )
|
||||
return 0;
|
||||
|
||||
info("The current word is: %s", word.c_str());
|
||||
return 1;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Keyboard callback
|
||||
static bool idaapi ct_keyboard(TWidget * /*v*/, int key, int shift, void *ud)
|
||||
{
|
||||
if ( shift == 0 )
|
||||
{
|
||||
sample_info_t *si = (sample_info_t *)ud;
|
||||
switch ( key )
|
||||
{
|
||||
case 'N':
|
||||
warning("The hotkey 'N' has been pressed");
|
||||
return true;
|
||||
case IK_ESCAPE:
|
||||
close_widget(si->cv, WCLS_SAVE | WCLS_CLOSE_LATER);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// This callback will be called each time the keyboard cursor position
|
||||
// is changed
|
||||
static void idaapi ct_curpos(TWidget *v, void *)
|
||||
{
|
||||
qstring word;
|
||||
if ( get_current_word(v, false, word) )
|
||||
msg("Current word is: %s\n", word.c_str());
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
ssize_t idaapi plugin_ctx_t::on_event(ssize_t code, va_list va)
|
||||
{
|
||||
switch ( code )
|
||||
{
|
||||
// how to implement a simple hint callback
|
||||
case ui_get_custom_viewer_hint:
|
||||
{
|
||||
qstring &hint = *va_arg(va, qstring *);
|
||||
TWidget *viewer = va_arg(va, TWidget *);
|
||||
place_t *place = va_arg(va, place_t *);
|
||||
int *important_lines = va_arg(va, int *);
|
||||
if ( si->cv == viewer ) // our viewer
|
||||
{
|
||||
if ( place == NULL )
|
||||
return 0;
|
||||
simpleline_place_t *spl = (simpleline_place_t *)place;
|
||||
hint.cat_sprnt("Hint for line %u\n", spl->n);
|
||||
*important_lines += 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ui_widget_invisible:
|
||||
{
|
||||
TWidget *f = va_arg(va, TWidget *);
|
||||
if ( f == si->cv )
|
||||
{
|
||||
delete si;
|
||||
si = nullptr;
|
||||
unhook_event_listener(HT_UI, this);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ui_populating_widget_popup:
|
||||
{
|
||||
TWidget *f = va_arg(va, TWidget *);
|
||||
if ( f == si->cv )
|
||||
{
|
||||
TPopupMenu *p = va_arg(va, TPopupMenu *);
|
||||
// Create right-click menu on the fly
|
||||
attach_action_to_popup(f, p, ACTION_NAME);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
static const custom_viewer_handlers_t handlers(
|
||||
ct_keyboard,
|
||||
NULL, // popup
|
||||
NULL, // mouse_moved
|
||||
NULL, // click
|
||||
NULL, // dblclick
|
||||
ct_curpos,
|
||||
NULL, // close
|
||||
NULL, // help
|
||||
NULL);// adjust_place
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Create a custom view window
|
||||
bool idaapi plugin_ctx_t::run(size_t)
|
||||
{
|
||||
TWidget *widget = find_widget("Sample custom view");
|
||||
if ( widget != NULL )
|
||||
{
|
||||
activate_widget(widget, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
// allocate block to hold info about our sample view
|
||||
si = new sample_info_t();
|
||||
last_si = si;
|
||||
// prepare the data to display. we could prepare it on the fly too.
|
||||
// but for that we have to use our own custom place_t class decendant.
|
||||
for ( int i=0; i < qnumber(sample_text); i++ )
|
||||
{
|
||||
si->sv.push_back(simpleline_t("")); // add empty line
|
||||
si->sv.push_back(simpleline_t(sample_text[i].text));
|
||||
si->sv.back().bgcolor = sample_text[i].color;
|
||||
}
|
||||
// create two place_t objects: for the minimal and maximal locations
|
||||
simpleline_place_t s1;
|
||||
simpleline_place_t s2(si->sv.size()-1);
|
||||
// create a custom viewer
|
||||
si->cv = create_custom_viewer("Sample custom view", &s1, &s2, &s1, NULL, &si->sv, &handlers, si);
|
||||
// also set the ui event callback
|
||||
hook_event_listener(HT_UI, this);
|
||||
// finally display the form on the screen
|
||||
display_widget(si->cv, WOPN_DP_TAB|WOPN_RESTORE);
|
||||
|
||||
// Register the action. This one will be attached
|
||||
// live, to the popup menu.
|
||||
register_action(sample_action);
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static plugmod_t *idaapi init()
|
||||
{
|
||||
return new plugin_ctx_t;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// PLUGIN DESCRIPTION BLOCK
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
plugin_t PLUGIN =
|
||||
{
|
||||
IDP_INTERFACE_VERSION,
|
||||
PLUGIN_MULTI, // plugin flags
|
||||
init, // initialize
|
||||
|
||||
nullptr,
|
||||
nullptr,
|
||||
|
||||
"", // long comment about the plugin
|
||||
"", // multiline help about the plugin
|
||||
"Sample custview", // the preferred short name of the plugin
|
||||
"" // the preferred hotkey to run the plugin
|
||||
};
|
||||
11
idasdk76/plugins/custview/makefile
Normal file
11
idasdk76/plugins/custview/makefile
Normal file
@@ -0,0 +1,11 @@
|
||||
PROC=custview
|
||||
|
||||
include ../plugin.mak
|
||||
|
||||
# MAKEDEP dependency list ------------------
|
||||
$(F)custview$(O): $(I)bitrange.hpp $(I)bytes.hpp $(I)config.hpp $(I)fpro.h \
|
||||
$(I)funcs.hpp $(I)ida.hpp $(I)idp.hpp $(I)ieee.h \
|
||||
$(I)kernwin.hpp $(I)lines.hpp $(I)llong.hpp \
|
||||
$(I)loader.hpp $(I)nalt.hpp $(I)netnode.hpp $(I)pro.h \
|
||||
$(I)range.hpp $(I)segment.hpp $(I)ua.hpp $(I)xref.hpp \
|
||||
custview.cpp
|
||||
171
idasdk76/plugins/dwarf/look_for_debug_file.cpp
Normal file
171
idasdk76/plugins/dwarf/look_for_debug_file.cpp
Normal file
@@ -0,0 +1,171 @@
|
||||
//-------------------------------------------------------------------------
|
||||
// Mimic GDB's debug file-seeking mechanism. Let:
|
||||
// PATH be for-each components of the full DWARF_DEBUG_FILE_DIRECTORY.
|
||||
// BIN be the full path to the binary file.
|
||||
// DLINK the value of the section ".gnu_debuglink"
|
||||
// BLDID build ID from note section GNU/3
|
||||
// BLDCAR the lowercase hex-formatted value of the first byte of BLDID
|
||||
// BLDCDR the lowercase hex-formatted value of the remaining bytes of BLDID
|
||||
//
|
||||
// 1) Look for file by build ID
|
||||
// foreach PATH in DWARF_DEBUG_FILE_DIRECTORY:
|
||||
// if $PATH/.build-id/$BLDCAR/$BLDCRD.debug exists and matches:
|
||||
// found!
|
||||
// 2) If not found, look for file by debug link
|
||||
// if dir($BIN)/$DLINK exists and matches:
|
||||
// found!
|
||||
// if dir($BIN)/.debug/$DLINK exists and matches:
|
||||
// found!
|
||||
// foreach PATH in DWARF_DEBUG_FILE_DIRECTORY:
|
||||
// if $PATH/dir($BIN)/$DLINK exists and matches:
|
||||
// found!
|
||||
class debug_info_file_visitor_t
|
||||
{
|
||||
public:
|
||||
char fullpath[MAXSTR]; // current path
|
||||
enum checkmethod_t
|
||||
{
|
||||
BUILDID,
|
||||
DEBUGLINK
|
||||
};
|
||||
|
||||
// visit fullpath
|
||||
// returns 0 - continue to search
|
||||
virtual int visit_fullpath(checkmethod_t check_method)
|
||||
{
|
||||
int code = 0;
|
||||
if ( qfileexist(fullpath) )
|
||||
{
|
||||
code = 1;
|
||||
if ( check_method == DEBUGLINK )
|
||||
code = check_debuglink_crc32() ? 1 : 0;
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
int call_visit_fullpath(checkmethod_t check_method)
|
||||
{
|
||||
int code = visit_fullpath(check_method);
|
||||
debugout("debug_info_file_visitor_t::visit_fullpath(check_method=%s), fullpath=%s => %d\n",
|
||||
check_method == BUILDID ? "BUILDID" : "DEBUGLINK",
|
||||
fullpath,
|
||||
code);
|
||||
return code;
|
||||
}
|
||||
|
||||
debug_info_file_visitor_t(
|
||||
const char *_glbl_deb_dirs, // global debug directories
|
||||
bool from_envvar, // taken from environment variable
|
||||
const char *_path_to_binary, // binary's absolute file name
|
||||
const char *_debuglink, // name of the separate debug info file
|
||||
uint32 _debuglink_crc32, // CRC32 of the separate debug info file
|
||||
const char *_buildid) // build ID
|
||||
: path_to_binary(_path_to_binary),
|
||||
debuglink(_debuglink),
|
||||
buildid(_buildid),
|
||||
debuglink_crc32(_debuglink_crc32)
|
||||
{
|
||||
fullpath[0] = '\0';
|
||||
const char *sep = from_envvar ? DELIMITER : ";"; //-V583
|
||||
char buf[QMAXPATH];
|
||||
qstrncpy(buf, _glbl_deb_dirs, sizeof(buf));
|
||||
char *saved_ptr;
|
||||
char *p = qstrtok(buf, sep, &saved_ptr);
|
||||
while ( p != NULL )
|
||||
{
|
||||
glbl_deb_dirs.push_back(p);
|
||||
p = qstrtok(NULL, sep, &saved_ptr);
|
||||
}
|
||||
}
|
||||
virtual ~debug_info_file_visitor_t() {}
|
||||
|
||||
// accept visitor
|
||||
// stop searching if visitor returns non-zero,
|
||||
// returns visitor's result
|
||||
int accept(void)
|
||||
{
|
||||
int code = 0;
|
||||
|
||||
// Look for file by build ID
|
||||
if ( !glbl_deb_dirs.empty() && !buildid.empty() )
|
||||
{
|
||||
// looks in the .build-id subdirectory of each one of the global debug directories
|
||||
// for a file named nn/nnnnnnnn.debug,
|
||||
// where nn are the first 2 hex characters of the build ID bit string,
|
||||
// and nnnnnnnn are the rest of the bit string
|
||||
qstring bid_car(buildid.c_str(), 2);
|
||||
qstring bid_cdr(buildid.c_str() + 2);
|
||||
bid_cdr.append(".debug");
|
||||
|
||||
for ( qstrvec_t::const_iterator p=glbl_deb_dirs.begin(); p != glbl_deb_dirs.end(); ++p )
|
||||
{
|
||||
qmakepath(fullpath, sizeof(fullpath), p->c_str(), ".build-id", bid_car.c_str(), bid_cdr.c_str(), NULL);
|
||||
code = call_visit_fullpath(BUILDID);
|
||||
if ( code != 0 )
|
||||
goto END;
|
||||
}
|
||||
}
|
||||
|
||||
// If not found, look for file by debug link
|
||||
if ( !debuglink.empty() )
|
||||
{
|
||||
char bindir[QMAXPATH];
|
||||
if ( qdirname(bindir, sizeof(bindir), path_to_binary.c_str()) )
|
||||
{
|
||||
// in the directory of the executable file
|
||||
qmakepath(fullpath, sizeof(fullpath), bindir, debuglink.c_str(), NULL);
|
||||
code = call_visit_fullpath(DEBUGLINK);
|
||||
if ( code != 0 )
|
||||
goto END;
|
||||
|
||||
// then in a subdirectory of that directory named .debug
|
||||
qmakepath(fullpath, sizeof(fullpath), bindir, ".debug", debuglink.c_str(), NULL);
|
||||
code = call_visit_fullpath(DEBUGLINK);
|
||||
if ( code != 0 )
|
||||
goto END;
|
||||
|
||||
// and finally under each one of the global debug directories,
|
||||
// in a subdirectory whose name is identical to the leading directories
|
||||
// of the executable's absolute file name
|
||||
for ( qstrvec_t::const_iterator p=glbl_deb_dirs.begin(); p != glbl_deb_dirs.end(); ++p )
|
||||
{
|
||||
qmakepath(fullpath, sizeof(fullpath), p->c_str(), bindir, debuglink.c_str(), NULL);
|
||||
code = call_visit_fullpath(DEBUGLINK);
|
||||
if ( code != 0 )
|
||||
goto END;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
END:
|
||||
return code;
|
||||
}
|
||||
|
||||
// check debuglink file CRC32
|
||||
bool check_debuglink_crc32(void)
|
||||
{
|
||||
linput_t *li = open_linput(fullpath, false);
|
||||
uint32 crc32 = calc_file_crc32(li);
|
||||
close_linput(li);
|
||||
return debuglink_crc32 == crc32;
|
||||
}
|
||||
|
||||
private:
|
||||
qstrvec_t glbl_deb_dirs;
|
||||
const qstring path_to_binary;
|
||||
const qstring debuglink;
|
||||
const qstring buildid;
|
||||
uint32 debuglink_crc32;
|
||||
|
||||
AS_PRINTF(2, 3) void debugout(const char *format, ...)
|
||||
{
|
||||
if ( (debug & LOOK_FOR_DEBUG_FILE_DEBUG_FLAG) != 0 )
|
||||
{
|
||||
va_list va;
|
||||
va_start(va, format);
|
||||
vmsg(format, va);
|
||||
va_end(va);
|
||||
}
|
||||
}
|
||||
};
|
||||
#undef DIFV_DEB
|
||||
143
idasdk76/plugins/ex_debidc/ex_debidc.cpp
Normal file
143
idasdk76/plugins/ex_debidc/ex_debidc.cpp
Normal file
@@ -0,0 +1,143 @@
|
||||
// Debugger IDC Helper
|
||||
// Executes IDC script when the process is launched
|
||||
// In fact, this approach can be used to hook IDC scripts to various debugger
|
||||
// events.
|
||||
|
||||
#include <ida.hpp>
|
||||
#include <idp.hpp>
|
||||
#include <dbg.hpp>
|
||||
#include <expr.hpp>
|
||||
#include <loader.hpp>
|
||||
|
||||
int data_id;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// The plugin stores the IDC file name in the database
|
||||
// It will create a node for this purpose
|
||||
static const char node_name[] = "$ debugger idc file";
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
struct plugin_ctx_t;
|
||||
|
||||
DECLARE_LISTENER(dbg_listener_t, plugin_ctx_t, ctx);
|
||||
DECLARE_LISTENER(idp_listener_t, plugin_ctx_t, ctx);
|
||||
|
||||
struct plugin_ctx_t : public plugmod_t
|
||||
{
|
||||
dbg_listener_t dbg_listener = dbg_listener_t(*this);
|
||||
idp_listener_t idp_listener = idp_listener_t(*this);
|
||||
plugin_ctx_t()
|
||||
{
|
||||
hook_event_listener(HT_DBG, &dbg_listener);
|
||||
hook_event_listener(HT_IDP, &idp_listener);
|
||||
set_module_data(&data_id, this);
|
||||
}
|
||||
~plugin_ctx_t()
|
||||
{
|
||||
clr_module_data(data_id);
|
||||
// listeners are uninstalled automatically
|
||||
// when the owner module is unloaded
|
||||
}
|
||||
|
||||
virtual bool idaapi run(size_t) override;
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Get the IDC file name from the database
|
||||
static bool get_idc_name(char *buf, size_t bufsize)
|
||||
{
|
||||
// access the node
|
||||
netnode mynode(node_name);
|
||||
// retrieve the value
|
||||
return mynode.valstr(buf, bufsize) > 0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Store the IDC file name in the database
|
||||
static void set_idc_name(const char *idc)
|
||||
{
|
||||
// access the node
|
||||
netnode mynode;
|
||||
// if it doesn't exist yet, create it
|
||||
// otherwise get its id
|
||||
mynode.create(node_name);
|
||||
// store the value
|
||||
mynode.set(idc, strlen(idc)+1);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
ssize_t idaapi idp_listener_t::on_event(ssize_t code, va_list va)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
ssize_t idaapi dbg_listener_t::on_event(ssize_t code, va_list /*va*/)
|
||||
{
|
||||
switch ( code )
|
||||
{
|
||||
case dbg_process_start:
|
||||
case dbg_process_attach:
|
||||
// it is time to run the script
|
||||
char idc[QMAXPATH];
|
||||
if ( get_idc_name(idc, sizeof(idc)) )
|
||||
{
|
||||
qstring errbuf;
|
||||
if ( !exec_idc_script(NULL, idc, "main", NULL, 0, &errbuf) )
|
||||
warning("%s", errbuf.c_str());
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
bool idaapi plugin_ctx_t::run(size_t)
|
||||
{
|
||||
// retrieve the old IDC name from the database
|
||||
char idc[QMAXPATH];
|
||||
if ( !get_idc_name(idc, sizeof(idc)) )
|
||||
qstrncpy(idc, "*.idc", sizeof(idc));
|
||||
|
||||
char *newidc = ask_file(false, idc, "Specify the script to run upon debugger launch");
|
||||
if ( newidc != NULL )
|
||||
{
|
||||
// store it back in the database
|
||||
set_idc_name(newidc);
|
||||
msg("Script %s will be run when the debugger is launched\n", newidc);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static plugmod_t *idaapi init()
|
||||
{
|
||||
// Our plugin works only for x86 PE executables
|
||||
processor_t &ph = PH;
|
||||
if ( ph.id != PLFM_386 || inf_get_filetype() != f_PE )
|
||||
return nullptr;
|
||||
return new plugin_ctx_t;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static const char wanted_name[] = "Specify Debugger IDC Script";
|
||||
static const char wanted_hotkey[] = "";
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// PLUGIN DESCRIPTION BLOCK
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
plugin_t PLUGIN =
|
||||
{
|
||||
IDP_INTERFACE_VERSION,
|
||||
PLUGIN_MULTI, // The plugin can work with multiple idbs in parallel
|
||||
init, // initialize
|
||||
nullptr,
|
||||
nullptr,
|
||||
wanted_name, // long comment about the plugin
|
||||
wanted_name, // multiline help about the plugin
|
||||
wanted_name, // the preferred short name of the plugin
|
||||
wanted_hotkey // the preferred hotkey to run the plugin
|
||||
};
|
||||
12
idasdk76/plugins/ex_debidc/makefile
Normal file
12
idasdk76/plugins/ex_debidc/makefile
Normal file
@@ -0,0 +1,12 @@
|
||||
PROC=ex_debidc
|
||||
|
||||
include ../plugin.mak
|
||||
|
||||
# MAKEDEP dependency list ------------------
|
||||
$(F)ex_debidc$(O): $(I)bitrange.hpp $(I)bytes.hpp $(I)config.hpp \
|
||||
$(I)dbg.hpp $(I)expr.hpp $(I)fpro.h \
|
||||
$(I)funcs.hpp $(I)ida.hpp $(I)idd.hpp $(I)idp.hpp \
|
||||
$(I)ieee.h $(I)kernwin.hpp $(I)lines.hpp $(I)llong.hpp \
|
||||
$(I)loader.hpp \
|
||||
$(I)nalt.hpp $(I)netnode.hpp $(I)pro.h $(I)range.hpp \
|
||||
$(I)segment.hpp $(I)ua.hpp $(I)xref.hpp ex_debidc.cpp
|
||||
85
idasdk76/plugins/ex_events1/ex_events1.cpp
Normal file
85
idasdk76/plugins/ex_events1/ex_events1.cpp
Normal file
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
This is a sample plugin.
|
||||
|
||||
It illustrates how the analysis can be improved
|
||||
|
||||
The plugin checks branch targets for newly created instructions.
|
||||
If the target does not exist in the program, the plugin
|
||||
forbids the instruction creation.
|
||||
|
||||
*/
|
||||
|
||||
#include <ida.hpp>
|
||||
#include <idp.hpp>
|
||||
#include <loader.hpp>
|
||||
#include <kernwin.hpp>
|
||||
#include <allins.hpp>
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
struct plugin_ctx_t : public plugmod_t, public event_listener_t
|
||||
{
|
||||
plugin_ctx_t()
|
||||
{
|
||||
hook_event_listener(HT_IDB, this);
|
||||
}
|
||||
~plugin_ctx_t()
|
||||
{
|
||||
// listeners are uninstalled automatically
|
||||
// when the owner module is unloaded
|
||||
}
|
||||
|
||||
virtual bool idaapi run(size_t) override;
|
||||
virtual ssize_t idaapi on_event(ssize_t code, va_list va) override;
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// This callback is called by the kernel when database related events happen
|
||||
ssize_t idaapi plugin_ctx_t::on_event(ssize_t event_id, va_list va)
|
||||
{
|
||||
switch ( event_id )
|
||||
{
|
||||
case idb_event::make_code: // An instruction is being created
|
||||
// args: insn_t *
|
||||
// returns: 1-ok, <=0-the kernel should stop
|
||||
insn_t *insn = va_arg(va, insn_t *);
|
||||
// we are interested in the branch instructions
|
||||
if ( insn->itype >= NN_ja && insn->itype <= NN_jmpshort )
|
||||
{
|
||||
// the first operand contains the jump target
|
||||
ea_t target = to_ea(insn->cs, insn->Op1.addr);
|
||||
if ( !is_mapped(target) )
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0; // event not processed
|
||||
// let other plugins handle it
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static plugmod_t *idaapi init()
|
||||
{
|
||||
return new plugin_ctx_t;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
bool idaapi plugin_ctx_t::run(size_t)
|
||||
{
|
||||
// since the plugin is fully automatic, there is nothing to do
|
||||
warning("Branch checker is fully automatic");
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
plugin_t PLUGIN =
|
||||
{
|
||||
IDP_INTERFACE_VERSION,
|
||||
PLUGIN_HIDE // Plugin should not appear in the Edit, Plugins menu
|
||||
| PLUGIN_MULTI, // The plugin can work with multiple idbs in parallel
|
||||
init, // initialize
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr, // long comment about the plugin
|
||||
nullptr, // multiline help about the plugin
|
||||
"Branch checker", // the preferred short name of the plugin
|
||||
nullptr, // the preferred hotkey to run the plugin
|
||||
};
|
||||
11
idasdk76/plugins/ex_events1/makefile
Normal file
11
idasdk76/plugins/ex_events1/makefile
Normal file
@@ -0,0 +1,11 @@
|
||||
PROC=ex_events1
|
||||
|
||||
include ../plugin.mak
|
||||
|
||||
# MAKEDEP dependency list ------------------
|
||||
$(F)ex_events1$(O): $(I)allins.hpp $(I)bitrange.hpp $(I)bytes.hpp \
|
||||
$(I)config.hpp $(I)fpro.h $(I)funcs.hpp $(I)ida.hpp \
|
||||
$(I)idp.hpp $(I)ieee.h $(I)kernwin.hpp $(I)lines.hpp \
|
||||
$(I)llong.hpp $(I)loader.hpp $(I)nalt.hpp \
|
||||
$(I)netnode.hpp $(I)pro.h $(I)range.hpp $(I)segment.hpp \
|
||||
$(I)ua.hpp $(I)xref.hpp ex_events1.cpp
|
||||
4
idasdk76/plugins/exports.def
Normal file
4
idasdk76/plugins/exports.def
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
global: PLUGIN;
|
||||
local: *;
|
||||
};
|
||||
166
idasdk76/plugins/extlang/extlang.cpp
Normal file
166
idasdk76/plugins/extlang/extlang.cpp
Normal file
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
This is a sample plugin. It illustrates
|
||||
|
||||
how to register a thid party language interpreter
|
||||
|
||||
*/
|
||||
|
||||
#include <ida.hpp>
|
||||
#include <idp.hpp>
|
||||
#include <loader.hpp>
|
||||
#include <expr.hpp>
|
||||
#include <kernwin.hpp>
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static bool idaapi compile_expr(// Compile an expression
|
||||
const char *name, // in: name of the function which will
|
||||
// hold the compiled expression
|
||||
ea_t current_ea, // in: current address. if unknown then BADADDR
|
||||
const char *expr, // in: expression to compile
|
||||
qstring *errbuf) // out: error message if compilation fails
|
||||
{ // Returns: success
|
||||
qnotused(name);
|
||||
qnotused(current_ea);
|
||||
qnotused(expr);
|
||||
// our toy interpreter doesn't support separate compilation/evaluation
|
||||
// some entry fields in ida won't be useable (bpt conditions, for example)
|
||||
if ( errbuf != NULL )
|
||||
*errbuf = "compilation error";
|
||||
return false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static bool idaapi call_func( // Evaluate a previously compiled expression
|
||||
idc_value_t *result, // out: function result
|
||||
const char *name, // in: function to call
|
||||
const idc_value_t args[], // in: input arguments
|
||||
size_t nargs, // in: number of input arguments
|
||||
qstring *errbuf) // out: error message if compilation fails
|
||||
{ // Returns: success
|
||||
qnotused(name);
|
||||
qnotused(nargs);
|
||||
qnotused(args);
|
||||
qnotused(result);
|
||||
if ( errbuf != NULL )
|
||||
*errbuf = "evaluation error";
|
||||
return false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
bool idaapi eval_expr( // Compile and evaluate expression
|
||||
idc_value_t *rv, // out: expression value
|
||||
ea_t current_ea, // in: current address. if unknown then BADADDR
|
||||
const char *expr, // in: expression to evaluation
|
||||
qstring *errbuf) // out: error message if compilation fails
|
||||
{ // Returns: success
|
||||
qnotused(current_ea);
|
||||
// we know to parse and decimal and hexadecimal numbers
|
||||
int radix = 10;
|
||||
const char *ptr = skip_spaces(expr);
|
||||
bool neg = false;
|
||||
if ( *ptr == '-' )
|
||||
{
|
||||
neg = true;
|
||||
ptr = skip_spaces(ptr+1);
|
||||
}
|
||||
if ( *ptr == '0' && *(ptr+1) == 'x' )
|
||||
{
|
||||
radix = 16;
|
||||
ptr += 2;
|
||||
}
|
||||
sval_t value = 0;
|
||||
while ( radix == 10 ? qisdigit(*ptr) : qisxdigit(*ptr) )
|
||||
{
|
||||
int d = *ptr <= '9' ? *ptr-'0' : qtolower(*ptr)-'a'+10;
|
||||
value *= radix;
|
||||
value += d;
|
||||
ptr++;
|
||||
}
|
||||
if ( neg )
|
||||
value = -value;
|
||||
ptr = skip_spaces(ptr);
|
||||
if ( *ptr != '\0' )
|
||||
{
|
||||
msg("EVAL FAILED: %s\n", expr);
|
||||
if ( errbuf != NULL )
|
||||
*errbuf = "syntax error";
|
||||
return false;
|
||||
}
|
||||
|
||||
// we have the result, store it in the return value
|
||||
if ( rv != nullptr )
|
||||
{
|
||||
rv->clear();
|
||||
rv->num = value;
|
||||
}
|
||||
msg("EVAL %" FMT_EA "d: %s\n", value, expr);
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
struct plugin_ctx_t : public plugmod_t
|
||||
{
|
||||
extlang_t my_extlang =
|
||||
{
|
||||
sizeof(extlang_t), // Size of this structure
|
||||
0, // Language features, currently 0
|
||||
0, // refcnt
|
||||
"extlang sample", // Language name
|
||||
nullptr, // fileext
|
||||
nullptr, // syntax highlighter
|
||||
compile_expr,
|
||||
nullptr, // compile_file
|
||||
call_func,
|
||||
eval_expr,
|
||||
nullptr, // create_object
|
||||
nullptr, // get_attr
|
||||
nullptr, // set_attr
|
||||
nullptr, // call_method
|
||||
nullptr, // eval_snippet
|
||||
nullptr, // load_procmod
|
||||
nullptr, // unload_procmod
|
||||
};
|
||||
bool installed = false;
|
||||
|
||||
plugin_ctx_t()
|
||||
{
|
||||
installed = install_extlang(&my_extlang) >= 0;
|
||||
}
|
||||
~plugin_ctx_t()
|
||||
{
|
||||
if ( installed )
|
||||
remove_extlang(&my_extlang);
|
||||
}
|
||||
|
||||
virtual bool idaapi run(size_t) override { return false; }
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static plugmod_t *idaapi init()
|
||||
{
|
||||
plugin_ctx_t *ctx = new plugin_ctx_t;
|
||||
if ( !ctx->installed )
|
||||
{
|
||||
msg("extlang: install_extlang() failed\n");
|
||||
delete ctx;
|
||||
ctx = nullptr;
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
plugin_t PLUGIN =
|
||||
{
|
||||
IDP_INTERFACE_VERSION,
|
||||
PLUGIN_HIDE // Plugin should not appear in the Edit, Plugins menu
|
||||
| PLUGIN_FIX // Load plugin when IDA starts and keep it in the
|
||||
// memory until IDA stops
|
||||
| PLUGIN_MULTI, // The plugin can work with multiple idbs in parallel
|
||||
init, // initialize
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr, // long comment about the plugin
|
||||
nullptr, // multiline help about the plugin
|
||||
"Sample third party language", // the preferred short name of the plugin
|
||||
nullptr, // the preferred hotkey to run the plugin
|
||||
};
|
||||
11
idasdk76/plugins/extlang/makefile
Normal file
11
idasdk76/plugins/extlang/makefile
Normal file
@@ -0,0 +1,11 @@
|
||||
PROC=extlang
|
||||
|
||||
include ../plugin.mak
|
||||
|
||||
# MAKEDEP dependency list ------------------
|
||||
$(F)extlang$(O) : $(I)bitrange.hpp $(I)bytes.hpp $(I)config.hpp \
|
||||
$(I)expr.hpp $(I)fpro.h $(I)funcs.hpp $(I)ida.hpp \
|
||||
$(I)idp.hpp $(I)ieee.h $(I)kernwin.hpp $(I)lines.hpp \
|
||||
$(I)llong.hpp $(I)loader.hpp $(I)nalt.hpp \
|
||||
$(I)netnode.hpp $(I)pro.h $(I)range.hpp $(I)segment.hpp \
|
||||
$(I)ua.hpp $(I)xref.hpp extlang.cpp
|
||||
8519
idasdk76/plugins/findcrypt2/consts.cpp
Normal file
8519
idasdk76/plugins/findcrypt2/consts.cpp
Normal file
File diff suppressed because it is too large
Load Diff
266
idasdk76/plugins/findcrypt2/findcrypt.cpp
Normal file
266
idasdk76/plugins/findcrypt2/findcrypt.cpp
Normal file
@@ -0,0 +1,266 @@
|
||||
// FindCrypt - find constants used in crypto algorithms
|
||||
// Copyright 2006 Ilfak Guilfanov <ig@hexblog.com>
|
||||
// This is a freeware program.
|
||||
// This copyright message must be kept intact.
|
||||
|
||||
// This plugin looks for constant arrays used in popular crypto algorithms.
|
||||
// If a crypto algorithm is found, it will rename the appropriate locations
|
||||
// of the program and put bookmarks on them.
|
||||
|
||||
// Version 2.0
|
||||
|
||||
#include <ida.hpp>
|
||||
#include <idp.hpp>
|
||||
#include <loader.hpp>
|
||||
#include <kernwin.hpp>
|
||||
#include <bytes.hpp>
|
||||
#include <name.hpp>
|
||||
#include <moves.hpp>
|
||||
#include <auto.hpp>
|
||||
|
||||
#include "findcrypt.hpp"
|
||||
|
||||
// #define VERIFY_CONSTANTS 1
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
struct plugin_ctx_t : public plugmod_t, public event_listener_t
|
||||
{
|
||||
plugin_ctx_t()
|
||||
{
|
||||
// agree to work with any database
|
||||
#ifndef TESTABLE_BUILD
|
||||
hook_event_listener(HT_IDP, this);
|
||||
#endif
|
||||
}
|
||||
~plugin_ctx_t()
|
||||
{
|
||||
// listeners are uninstalled automatically
|
||||
// when the owner module is unloaded
|
||||
}
|
||||
|
||||
virtual bool idaapi run(size_t) override;
|
||||
virtual ssize_t idaapi on_event(ssize_t code, va_list va) override;
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// retrieve the first byte of the specified array
|
||||
// take into account the byte sex
|
||||
inline uchar get_first_byte(const array_info_t *a)
|
||||
{
|
||||
const uchar *ptr = (const uchar *)a->array;
|
||||
if ( !inf_is_be() )
|
||||
return ptr[0];
|
||||
return ptr[a->elsize-1];
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// check that all constant arrays are distinct (no duplicates)
|
||||
//lint -e528 not used
|
||||
#ifdef VERIFY_CONSTANTS
|
||||
static void verify_constants(const array_info_t *consts)
|
||||
{
|
||||
typedef std::set<qstring> strset_t;
|
||||
strset_t myset;
|
||||
for ( const array_info_t *ptr=consts; ptr->size != 0; ptr++ )
|
||||
{
|
||||
qstring s((char*)ptr->array, ptr->size);
|
||||
if ( !myset.insert(s).second )
|
||||
error("duplicate array %s!", ptr->name);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// match a constant array against the database at the specified address
|
||||
static bool match_array_pattern(ea_t ea, const array_info_t *ai)
|
||||
{
|
||||
uchar *ptr = (uchar *)ai->array;
|
||||
for ( size_t i=0; i < ai->size; i++ )
|
||||
{
|
||||
switch ( ai->elsize )
|
||||
{
|
||||
case 1:
|
||||
if ( get_byte(ea) != *(uchar*)ptr )
|
||||
return false;
|
||||
break;
|
||||
case 2:
|
||||
if ( get_word(ea) != *(ushort*)ptr )
|
||||
return false;
|
||||
break;
|
||||
case 4:
|
||||
if ( get_dword(ea) != *(uint32*)ptr )
|
||||
return false;
|
||||
break;
|
||||
case 8:
|
||||
if ( get_qword(ea) != *(uint64*)ptr )
|
||||
return false;
|
||||
break;
|
||||
default:
|
||||
error("interr: unexpected array '%s' element size %" FMT_Z,
|
||||
ai->name, ai->elsize);
|
||||
}
|
||||
ptr += ai->elsize;
|
||||
ea += ai->elsize;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// match a sparse array against the database at the specified address
|
||||
// NB: all sparse arrays must be word32!
|
||||
static bool match_sparse_pattern(ea_t ea, const array_info_t *ai)
|
||||
{
|
||||
const word32 *ptr = (const word32*)ai->array;
|
||||
if ( get_dword(ea) != *ptr++ )
|
||||
return false;
|
||||
ea += 4;
|
||||
for ( size_t i=1; i < ai->size; i++ )
|
||||
{
|
||||
word32 c = *ptr++;
|
||||
if ( inf_is_be() )
|
||||
c = swap32(c);
|
||||
// look for the constant in the next N bytes
|
||||
const size_t N = 64;
|
||||
uchar mem[N+4];
|
||||
memset(mem, 0xFF, sizeof(mem));
|
||||
get_bytes(mem, sizeof(mem), ea);
|
||||
int j;
|
||||
for ( j=0; j < N; j++ )
|
||||
if ( *(uint32*)(mem+j) == c )
|
||||
break;
|
||||
if ( j == N )
|
||||
return false;
|
||||
ea += j + 4;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// mark a location with the name of the algorithm
|
||||
// use the first free slot for the marker
|
||||
static void mark_location(ea_t ea, const char *name)
|
||||
{
|
||||
idaplace_t ipl(ea, 0);
|
||||
renderer_info_t rinfo;
|
||||
rinfo.rtype = TCCRT_FLAT;
|
||||
rinfo.pos.cx = 0;
|
||||
rinfo.pos.cy = 5;
|
||||
lochist_entry_t e(&ipl, rinfo);
|
||||
|
||||
uint32 i, n = bookmarks_t::size(e, NULL);
|
||||
for ( i = 0; i < n; ++i )
|
||||
{
|
||||
qstring desc;
|
||||
lochist_entry_t loc(e);
|
||||
if ( !bookmarks_t::get(&loc, &desc, &i, NULL) )
|
||||
break;
|
||||
// reuse old "Crypto: " slots
|
||||
if ( strneq(desc.c_str(), "Crypto: ", 7) && loc.place()->toea() == ea )
|
||||
break;
|
||||
}
|
||||
qstring buf;
|
||||
buf.sprnt("Crypto: %s", name);
|
||||
bookmarks_t::mark(e, i, NULL, buf.c_str(), NULL);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// try to find constants at the given address range
|
||||
static void recognize_constants(ea_t ea1, ea_t ea2)
|
||||
{
|
||||
int count = 0;
|
||||
show_wait_box("Searching for crypto constants...");
|
||||
for ( ea_t ea=ea1; ea < ea2; ea=next_addr(ea) )
|
||||
{
|
||||
if ( (ea % 0x1000) == 0 )
|
||||
{
|
||||
show_addr(ea);
|
||||
if ( user_cancelled() )
|
||||
break;
|
||||
}
|
||||
uchar b = get_byte(ea);
|
||||
// check against normal constants
|
||||
for ( const array_info_t *ptr=non_sparse_consts; ptr->size != 0; ptr++ )
|
||||
{
|
||||
if ( b != get_first_byte(ptr) )
|
||||
continue;
|
||||
if ( match_array_pattern(ea, ptr) )
|
||||
{
|
||||
msg("%a: found const array %s (used in %s)\n", ea, ptr->name, ptr->algorithm);
|
||||
mark_location(ea, ptr->algorithm);
|
||||
force_name(ea, ptr->name);
|
||||
count++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// check against sparse constants
|
||||
for ( const array_info_t *ptr=sparse_consts; ptr->size != 0; ptr++ )
|
||||
{
|
||||
if ( b != get_first_byte(ptr) )
|
||||
continue;
|
||||
if ( match_sparse_pattern(ea, ptr) )
|
||||
{
|
||||
msg("%a: found sparse constants for %s\n", ea, ptr->algorithm);
|
||||
mark_location(ea, ptr->algorithm);
|
||||
count++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
hide_wait_box();
|
||||
if ( count != 0 )
|
||||
msg("Found %d known constant arrays in total.\n", count);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// This callback is called for IDP notification events
|
||||
ssize_t idaapi plugin_ctx_t::on_event(ssize_t code, va_list /*va*/)
|
||||
{
|
||||
if ( code == processor_t::ev_newfile ) // a new file has been loaded
|
||||
recognize_constants(inf_get_min_ea(), inf_get_max_ea());
|
||||
return 0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
bool idaapi plugin_ctx_t::run(size_t)
|
||||
{
|
||||
ea_t ea1;
|
||||
ea_t ea2;
|
||||
read_range_selection(NULL, &ea1, &ea2); // if fails, inf.min_ea and inf.max_ea will be used
|
||||
recognize_constants(ea1, ea2);
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static plugmod_t *idaapi init()
|
||||
{
|
||||
#ifdef VERIFY_CONSTANTS
|
||||
verify_constants(non_sparse_consts);
|
||||
verify_constants(sparse_consts);
|
||||
#endif
|
||||
return new plugin_ctx_t;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static const char help[] = "Find crypt v2";
|
||||
static const char comment[] = "Find crypt v2";
|
||||
static const char wanted_name[] = "Find crypt v2";
|
||||
static const char wanted_hotkey[] = "";
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// PLUGIN DESCRIPTION BLOCK
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
plugin_t PLUGIN =
|
||||
{
|
||||
IDP_INTERFACE_VERSION,
|
||||
PLUGIN_PROC // Load plugin when a processor module is loaded
|
||||
| PLUGIN_MULTI, // The plugin can work with multiple idbs in parallel
|
||||
init, // initialize
|
||||
nullptr,
|
||||
nullptr,
|
||||
comment, // long comment about the plugin
|
||||
help, // multiline help about the plugin
|
||||
wanted_name, // the preferred short name of the plugin
|
||||
wanted_hotkey // the preferred hotkey to run the plugin
|
||||
};
|
||||
31
idasdk76/plugins/findcrypt2/findcrypt.hpp
Normal file
31
idasdk76/plugins/findcrypt2/findcrypt.hpp
Normal file
@@ -0,0 +1,31 @@
|
||||
|
||||
#define IS_LITTLE_ENDIAN
|
||||
|
||||
#if defined(__GNUC__) || defined(__MWERKS__)
|
||||
#define WORD64_AVAILABLE
|
||||
typedef unsigned long long word64;
|
||||
typedef unsigned long word32;
|
||||
typedef unsigned char byte;
|
||||
#define W64LIT(x) x##LL
|
||||
#elif defined(_MSC_VER) || defined(__BCPLUSPLUS__)
|
||||
#define WORD64_AVAILABLE
|
||||
typedef unsigned __int64 word64;
|
||||
typedef unsigned __int32 word32;
|
||||
typedef unsigned __int8 byte;
|
||||
#define W64LIT(x) x##ui64
|
||||
#endif
|
||||
|
||||
struct array_info_t
|
||||
{
|
||||
const void *array;
|
||||
size_t size;
|
||||
size_t elsize;
|
||||
const char *name;
|
||||
const char *algorithm;
|
||||
};
|
||||
|
||||
extern const array_info_t non_sparse_consts[];
|
||||
extern const array_info_t sparse_consts[];
|
||||
|
||||
#define ARR(x) x, qnumber(x), sizeof(x[0]), #x
|
||||
|
||||
16
idasdk76/plugins/findcrypt2/makefile
Normal file
16
idasdk76/plugins/findcrypt2/makefile
Normal file
@@ -0,0 +1,16 @@
|
||||
PROC=findcrypt
|
||||
O1=consts
|
||||
O2=sparse
|
||||
|
||||
include ../plugin.mak
|
||||
|
||||
# MAKEDEP dependency list ------------------
|
||||
$(F)consts$(O) : $(I)llong.hpp $(I)pro.h consts.cpp findcrypt.hpp
|
||||
$(F)findcrypt$(O): $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
|
||||
$(I)config.hpp $(I)dirtree.hpp $(I)fpro.h $(I)funcs.hpp \
|
||||
$(I)ida.hpp $(I)idp.hpp $(I)ieee.h $(I)kernwin.hpp \
|
||||
$(I)lines.hpp $(I)llong.hpp $(I)loader.hpp $(I)moves.hpp \
|
||||
$(I)nalt.hpp $(I)name.hpp $(I)netnode.hpp $(I)pro.h \
|
||||
$(I)range.hpp $(I)segment.hpp $(I)ua.hpp \
|
||||
$(I)xref.hpp findcrypt.cpp findcrypt.hpp
|
||||
$(F)sparse$(O) : $(I)llong.hpp $(I)pro.h findcrypt.hpp sparse.cpp
|
||||
122
idasdk76/plugins/findcrypt2/sparse.cpp
Normal file
122
idasdk76/plugins/findcrypt2/sparse.cpp
Normal file
@@ -0,0 +1,122 @@
|
||||
#include <pro.h>
|
||||
#include "findcrypt.hpp"
|
||||
|
||||
// Various constants used in crypto algorithms
|
||||
// They were copied from public domain codes
|
||||
|
||||
static const word32 SHA_1[] =
|
||||
{
|
||||
0x67452301L,
|
||||
0xEFCDAB89L,
|
||||
0x98BADCFEL,
|
||||
0x10325476L,
|
||||
0xC3D2E1F0L,
|
||||
};
|
||||
|
||||
static const word32 RC5_RC6[] =
|
||||
{
|
||||
0xb7e15163L, // magic constant P for wordsize
|
||||
0x9e3779b9L, // magic constant Q for wordsize
|
||||
};
|
||||
|
||||
static const word32 MD5[] =
|
||||
{
|
||||
0xd76aa478,
|
||||
0xe8c7b756,
|
||||
0x242070db,
|
||||
0xc1bdceee,
|
||||
0xf57c0faf,
|
||||
0x4787c62a,
|
||||
0xa8304613,
|
||||
0xfd469501,
|
||||
0x698098d8,
|
||||
0x8b44f7af,
|
||||
0xffff5bb1,
|
||||
0x895cd7be,
|
||||
0x6b901122,
|
||||
0xfd987193,
|
||||
0xa679438e,
|
||||
0x49b40821,
|
||||
|
||||
0xf61e2562,
|
||||
0xc040b340,
|
||||
0x265e5a51,
|
||||
0xe9b6c7aa,
|
||||
0xd62f105d,
|
||||
0x02441453,
|
||||
0xd8a1e681,
|
||||
0xe7d3fbc8,
|
||||
0x21e1cde6,
|
||||
0xc33707d6,
|
||||
0xf4d50d87,
|
||||
0x455a14ed,
|
||||
0xa9e3e905,
|
||||
0xfcefa3f8,
|
||||
0x676f02d9,
|
||||
0x8d2a4c8a,
|
||||
|
||||
0xfffa3942,
|
||||
0x8771f681,
|
||||
0x6d9d6122,
|
||||
0xfde5380c,
|
||||
0xa4beea44,
|
||||
0x4bdecfa9,
|
||||
0xf6bb4b60,
|
||||
0xbebfbc70,
|
||||
0x289b7ec6,
|
||||
0xeaa127fa,
|
||||
0xd4ef3085,
|
||||
0x04881d05,
|
||||
0xd9d4d039,
|
||||
0xe6db99e5,
|
||||
0x1fa27cf8,
|
||||
0xc4ac5665,
|
||||
|
||||
0xf4292244,
|
||||
0x432aff97,
|
||||
0xab9423a7,
|
||||
0xfc93a039,
|
||||
0x655b59c3,
|
||||
0x8f0ccc92,
|
||||
0xffeff47d,
|
||||
0x85845dd1,
|
||||
0x6fa87e4f,
|
||||
0xfe2ce6e0,
|
||||
0xa3014314,
|
||||
0x4e0811a1,
|
||||
0xf7537e82,
|
||||
0xbd3af235,
|
||||
0x2ad7d2bb,
|
||||
0xeb86d391,
|
||||
};
|
||||
|
||||
static const word32 MD4[] =
|
||||
{
|
||||
0x67452301L,
|
||||
0xefcdab89L,
|
||||
0x98badcfeL,
|
||||
0x10325476L,
|
||||
};
|
||||
|
||||
static const word32 HAVAL[] =
|
||||
{
|
||||
0x243F6A88,
|
||||
0x85A308D3,
|
||||
0x13198A2E,
|
||||
0x03707344,
|
||||
0xA4093822,
|
||||
0x299F31D0,
|
||||
0x082EFA98,
|
||||
0xEC4E6C89,
|
||||
};
|
||||
|
||||
// NB: all sparse arrays must be word32!
|
||||
const array_info_t sparse_consts[] =
|
||||
{
|
||||
{ ARR(SHA_1), "SHA-1" },
|
||||
{ ARR(RC5_RC6), "RC5_RC6" },
|
||||
{ ARR(MD5), "MD5" },
|
||||
{ ARR(MD4), "MD4" },
|
||||
{ ARR(HAVAL), "HAVAL" },
|
||||
{ NULL, 0, 0, NULL, NULL }
|
||||
};
|
||||
316
idasdk76/plugins/formchooser/formchooser.cpp
Normal file
316
idasdk76/plugins/formchooser/formchooser.cpp
Normal file
@@ -0,0 +1,316 @@
|
||||
/*
|
||||
* This plugin demonstrates how to use choosers inside forms.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <ida.hpp>
|
||||
#include <idp.hpp>
|
||||
#include <loader.hpp>
|
||||
#include <kernwin.hpp>
|
||||
|
||||
#define ACTION_NAME "formchooser:action"
|
||||
#define TITLE_PFX "Form with choosers"
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// raw data of the png icon (16x16)
|
||||
static const unsigned char icon_data[182] =
|
||||
{
|
||||
0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52,
|
||||
0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x08, 0x06, 0x00, 0x00, 0x00, 0x1F, 0xF3, 0xFF,
|
||||
0x61, 0x00, 0x00, 0x00, 0x7D, 0x49, 0x44, 0x41, 0x54, 0x78, 0xDA, 0x63, 0x64, 0xC0, 0x0E, 0xFE,
|
||||
0xE3, 0x10, 0x67, 0x24, 0x28, 0x00, 0xD2, 0xFC, 0xF3, 0xAF, 0x36, 0x56, 0xDD, 0xEC, 0xCC, 0x57,
|
||||
0x31, 0xF4, 0x20, 0x73, 0xC0, 0xB6, 0xE2, 0xD2, 0x8C, 0x66, 0x08, 0x5C, 0x2F, 0x8A, 0x01, 0x84,
|
||||
0x34, 0x63, 0x73, 0x09, 0x23, 0xA9, 0x9A, 0xD1, 0x0D, 0x61, 0x44, 0xD7, 0xCC, 0xCF, 0x02, 0x71,
|
||||
0xE2, 0xC7, 0x3F, 0xA8, 0x06, 0x62, 0x13, 0x07, 0x19, 0x42, 0x7D, 0x03, 0x48, 0xF5, 0xC6, 0x20,
|
||||
0x34, 0x00, 0xE4, 0x57, 0x74, 0xFF, 0xE3, 0x92, 0x83, 0x19, 0xC0, 0x40, 0x8C, 0x21, 0xD8, 0x34,
|
||||
0x33, 0x40, 0xA3, 0x91, 0x01, 0x97, 0x21, 0xC8, 0x00, 0x9B, 0x66, 0x38, 0x01, 0x33, 0x00, 0x44,
|
||||
0x50, 0x92, 0x94, 0xB1, 0xBA, 0x04, 0x8B, 0x66, 0x9C, 0x99, 0x09, 0xC5, 0x10, 0x1C, 0xE2, 0x18,
|
||||
0xEA, 0x01, 0xA3, 0x65, 0x55, 0x0B, 0x33, 0x14, 0x07, 0x63, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45,
|
||||
0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
struct formchooser_ah_t : public action_handler_t
|
||||
{
|
||||
virtual int idaapi activate(action_activation_ctx_t *ctx) override
|
||||
{
|
||||
msg("Menu item clicked. Current selection:");
|
||||
for ( size_t i = 0, n = ctx->chooser_selection.size(); i < n; ++i )
|
||||
msg(" %" FMT_Z, ctx->chooser_selection[i]);
|
||||
msg("\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
virtual action_state_t idaapi update(action_update_ctx_t *ctx) override
|
||||
{
|
||||
bool ok = ctx->widget_type == BWN_CHOOSER;
|
||||
if ( ok )
|
||||
{
|
||||
qstring name;
|
||||
ok = get_widget_title(&name, ctx->widget)
|
||||
&& strneq(name.c_str(), TITLE_PFX, qstrlen(TITLE_PFX));
|
||||
}
|
||||
return ok ? AST_ENABLE_FOR_WIDGET : AST_DISABLE_FOR_WIDGET;
|
||||
}
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//lint -e{958} padding needed
|
||||
struct plugin_ctx_t : public plugmod_t
|
||||
{
|
||||
int icon_id = load_custom_icon(icon_data, sizeof(icon_data), "png");
|
||||
|
||||
formchooser_ah_t formchooser_ah;
|
||||
const action_desc_t formchooser_desc = ACTION_DESC_LITERAL_PLUGMOD(
|
||||
ACTION_NAME,
|
||||
"Test",
|
||||
&formchooser_ah,
|
||||
this,
|
||||
"Ctrl-K",
|
||||
nullptr,
|
||||
icon_id);
|
||||
|
||||
int main_current_index = -1;
|
||||
|
||||
virtual bool idaapi run(size_t) override;
|
||||
|
||||
static int idaapi modcb(int fid, form_actions_t &fa);
|
||||
void refresh_selection_edit(form_actions_t & fa);
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
struct mainch_chooser_t : public chooser_t
|
||||
{
|
||||
protected:
|
||||
static const int widths_[];
|
||||
static const char *const header_[];
|
||||
friend struct auxch_chooser_t;
|
||||
|
||||
public:
|
||||
// this chooser is embedded into the modal form
|
||||
inline mainch_chooser_t(int icon_id);
|
||||
|
||||
virtual size_t idaapi get_count() const override { return 10; }
|
||||
virtual void idaapi get_row(
|
||||
qstrvec_t *cols,
|
||||
int *icon_,
|
||||
chooser_item_attrs_t *attrs,
|
||||
size_t n) const override;
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
struct auxch_chooser_t : public chooser_multi_t
|
||||
{
|
||||
public:
|
||||
plugin_ctx_t &ctx;
|
||||
|
||||
// this chooser is embedded into the modal form
|
||||
auxch_chooser_t(plugin_ctx_t &ctx, int icon_id);
|
||||
|
||||
virtual size_t idaapi get_count() const override
|
||||
{
|
||||
return ctx.main_current_index + 1;
|
||||
}
|
||||
virtual void idaapi get_row(
|
||||
qstrvec_t *cols,
|
||||
int *icon_,
|
||||
chooser_item_attrs_t *attrs,
|
||||
size_t n) const override;
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
const int mainch_chooser_t::widths_[] = { 40 };
|
||||
const char *const mainch_chooser_t::header_[] = { "Item" };
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
inline mainch_chooser_t::mainch_chooser_t(int icon_)
|
||||
: chooser_t(CH_KEEP | CH_NOIDB,
|
||||
qnumber(widths_), widths_, header_)
|
||||
{
|
||||
CASSERT(qnumber(widths_) == qnumber(header_));
|
||||
icon = icon_;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
void idaapi mainch_chooser_t::get_row(
|
||||
qstrvec_t *cols_,
|
||||
int *,
|
||||
chooser_item_attrs_t *,
|
||||
size_t n) const
|
||||
{
|
||||
qstrvec_t &cols = *cols_;
|
||||
cols[0].sprnt("Option %" FMT_Z, n + 1);
|
||||
CASSERT(qnumber(header_) == 1);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
auxch_chooser_t::auxch_chooser_t(plugin_ctx_t &ctx_, int icon_)
|
||||
: chooser_multi_t(
|
||||
CH_KEEP | CH_NOIDB,
|
||||
qnumber(mainch_chooser_t::widths_),
|
||||
mainch_chooser_t::widths_,
|
||||
mainch_chooser_t::header_),
|
||||
ctx(ctx_)
|
||||
{
|
||||
icon = icon_;
|
||||
}
|
||||
//-------------------------------------------------------------------------
|
||||
void idaapi auxch_chooser_t::get_row(
|
||||
qstrvec_t *cols_,
|
||||
int *,
|
||||
chooser_item_attrs_t *,
|
||||
size_t n) const
|
||||
{
|
||||
qstrvec_t &cols = *cols_;
|
||||
cols[0].sprnt("Item %" FMT_Z, n + 1);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
void plugin_ctx_t::refresh_selection_edit(form_actions_t & fa)
|
||||
{
|
||||
qstring str;
|
||||
if ( main_current_index == -1 )
|
||||
{
|
||||
str = "No selection";
|
||||
}
|
||||
else
|
||||
{
|
||||
str.sprnt("Main %d", main_current_index + 1);
|
||||
|
||||
sizevec_t array;
|
||||
fa.get_chooser_value(4, &array);
|
||||
if ( array.size() > 0 )
|
||||
{
|
||||
str.append(" - Aux item(s) ");
|
||||
for ( int i = 0; i < array.size(); i++ )
|
||||
{
|
||||
if ( i != 0 )
|
||||
str.append(", ");
|
||||
str.cat_sprnt("%" FMT_Z, array[i] + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
fa.set_string_value(5, &str);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
int idaapi plugin_ctx_t::modcb(int fid, form_actions_t &fa)
|
||||
{
|
||||
plugin_ctx_t &ctx = *(plugin_ctx_t *)fa.get_ud();
|
||||
switch ( fid )
|
||||
{
|
||||
case CB_INIT:
|
||||
msg("initializing\n");
|
||||
ctx.refresh_selection_edit(fa);
|
||||
break;
|
||||
case CB_YES:
|
||||
msg("terminating\n");
|
||||
break;
|
||||
// main chooser
|
||||
case 3:
|
||||
{
|
||||
msg("main chooser selection change\n");
|
||||
sizevec_t array;
|
||||
fa.get_chooser_value(3, &array);
|
||||
ctx.main_current_index = !array.empty() ? array[0] : -1;
|
||||
// refresh auxiliar chooser
|
||||
fa.refresh_field(4);
|
||||
ctx.refresh_selection_edit(fa);
|
||||
}
|
||||
break;
|
||||
// auxiliar chooser
|
||||
case 4:
|
||||
ctx.refresh_selection_edit(fa);
|
||||
break;
|
||||
// Aux value text control
|
||||
case 5:
|
||||
break;
|
||||
default:
|
||||
msg("unknown id %d\n", fid);
|
||||
break;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
bool idaapi plugin_ctx_t::run(size_t)
|
||||
{
|
||||
struct ida_local lambda_t
|
||||
{
|
||||
static ssize_t idaapi cb(void *, int code, va_list va)
|
||||
{
|
||||
if ( code == ui_finish_populating_widget_popup )
|
||||
{
|
||||
TWidget *widget = va_arg(va, TWidget *);
|
||||
TPopupMenu *popup_handle = va_arg(va, TPopupMenu *);
|
||||
// Let the chooser populate itself normally first.
|
||||
// We'll add our own stuff on second pass.
|
||||
qstring buf;
|
||||
if ( get_widget_type(widget) == BWN_CHOOSER
|
||||
&& get_widget_title(&buf, widget)
|
||||
&& buf == TITLE_PFX":3" )
|
||||
{
|
||||
attach_action_to_popup(widget, popup_handle, ACTION_NAME);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
hook_to_notification_point(HT_UI, lambda_t::cb);
|
||||
|
||||
static const char form[] =
|
||||
"STARTITEM 0\n"
|
||||
TITLE_PFX"\n\n"
|
||||
"%/%*"
|
||||
"Select an item in the main chooser:\n"
|
||||
"\n"
|
||||
"<Main chooser:E3::30::><Auxiliar chooser (multi):E4::30::>\n\n"
|
||||
"<Selection:q5:1023:40::>\n"
|
||||
"\n";
|
||||
|
||||
register_action(formchooser_desc);
|
||||
|
||||
mainch_chooser_t main_ch(icon_id);
|
||||
sizevec_t main_sel; // no selection by default
|
||||
main_current_index = -1;
|
||||
|
||||
auxch_chooser_t aux_ch(*this, icon_id);
|
||||
sizevec_t aux_sel; // no selection by default
|
||||
|
||||
qstring str;
|
||||
|
||||
CASSERT(IS_CHOOSER_BASE_T(main_ch));
|
||||
CASSERT(IS_CHOOSER_BASE_T(aux_ch));
|
||||
if ( ask_form(form, modcb, this,
|
||||
&main_ch, &main_sel,
|
||||
&aux_ch, &aux_sel,
|
||||
&str) > 0 )
|
||||
{
|
||||
msg("Selection: %s\n", str.c_str());
|
||||
}
|
||||
|
||||
unhook_from_notification_point(HT_UI, lambda_t::cb);
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static plugmod_t *idaapi init()
|
||||
{
|
||||
return new plugin_ctx_t;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
plugin_t PLUGIN =
|
||||
{
|
||||
IDP_INTERFACE_VERSION,
|
||||
PLUGIN_UNL // Unload the plugin immediately after calling 'run'
|
||||
| PLUGIN_MULTI, // The plugin can work with multiple idbs in parallel
|
||||
init,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
"Forms chooser sample",// the preferred short name of the plugin
|
||||
nullptr,
|
||||
};
|
||||
204
idasdk76/plugins/formchooser/formchooser.py
Normal file
204
idasdk76/plugins/formchooser/formchooser.py
Normal file
@@ -0,0 +1,204 @@
|
||||
import idaapi
|
||||
from ida_kernwin import Choose, Form
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
class MainChooserClass(Choose):
|
||||
def __init__(self, title, icon):
|
||||
Choose.__init__(self,
|
||||
title,
|
||||
[ ["Item", 10] ],
|
||||
icon=icon,
|
||||
flags=Choose.CH_NOIDB,
|
||||
embedded=True, width=30, height=20)
|
||||
|
||||
def OnGetLine(self, n):
|
||||
return ["Option %d" % (n + 1)]
|
||||
|
||||
def OnGetSize(self):
|
||||
return 10
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
class AuxChooserClass(Choose):
|
||||
def __init__(self, title, icon):
|
||||
Choose.__init__(self,
|
||||
title,
|
||||
[ ["Item", 10] ],
|
||||
icon=icon,
|
||||
flags=Choose.CH_NOIDB | Choose.CH_MULTI,
|
||||
embedded=True, width=30, height=20)
|
||||
|
||||
def OnGetLine(self, n):
|
||||
return ["Item %d" % (n + 1)]
|
||||
|
||||
def OnGetSize(self):
|
||||
return self.form.main_current_index + 1
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
class TestActionHandler(idaapi.action_handler_t):
|
||||
def __init__(self, chooser):
|
||||
idaapi.action_handler_t.__init__(self)
|
||||
self.chooser = chooser
|
||||
|
||||
def activate(self, ctx):
|
||||
sel = []
|
||||
for idx in ctx.chooser_selection:
|
||||
sel.append(str(idx))
|
||||
print("Menu item clicked. Current selection: %s" % sel);
|
||||
|
||||
def update(self, ctx):
|
||||
return idaapi.AST_ENABLE_ALWAYS
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
class MyChooserForm(Form):
|
||||
|
||||
# Custom icon data
|
||||
icon_data = (
|
||||
b"\x89\x50\x4E\x47\x0D\x0A\x1A\x0A\x00\x00\x00\x0D\x49\x48\x44\x52"
|
||||
b"\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\x00\x00\x00\x1F\xF3\xFF"
|
||||
b"\x61\x00\x00\x00\x7D\x49\x44\x41\x54\x78\xDA\x63\x64\xC0\x0E\xFE"
|
||||
b"\xE3\x10\x67\x24\x28\x00\xD2\xFC\xF3\xAF\x36\x56\xDD\xEC\xCC\x57"
|
||||
b"\x31\xF4\x20\x73\xC0\xB6\xE2\xD2\x8C\x66\x08\x5C\x2F\x8A\x01\x84"
|
||||
b"\x34\x63\x73\x09\x23\xA9\x9A\xD1\x0D\x61\x44\xD7\xCC\xCF\x02\x71"
|
||||
b"\xE2\xC7\x3F\xA8\x06\x62\x13\x07\x19\x42\x7D\x03\x48\xF5\xC6\x20"
|
||||
b"\x34\x00\xE4\x57\x74\xFF\xE3\x92\x83\x19\xC0\x40\x8C\x21\xD8\x34"
|
||||
b"\x33\x40\xA3\x91\x01\x97\x21\xC8\x00\x9B\x66\x38\x01\x33\x00\x44"
|
||||
b"\x50\x92\x94\xB1\xBA\x04\x8B\x66\x9C\x99\x09\xC5\x10\x1C\xE2\x18"
|
||||
b"\xEA\x01\xA3\x65\x55\x0B\x33\x14\x07\x63\x00\x00\x00\x00\x49\x45"
|
||||
b"\x4E\x44\xAE\x42\x60\x82")
|
||||
|
||||
TITLE_PFX = "Form with choosers"
|
||||
|
||||
|
||||
def Free(self):
|
||||
self.hooks.unhook()
|
||||
self.hooks = None
|
||||
|
||||
# Call the base
|
||||
Form.Free(self)
|
||||
|
||||
# Free icon
|
||||
if self.icon_id != 0:
|
||||
idaapi.free_custom_icon(self.icon_id)
|
||||
self.icon_id = 0
|
||||
|
||||
# Remove local bindings
|
||||
self.EChMain = None
|
||||
self.EChAux = None
|
||||
|
||||
|
||||
def __init__(self):
|
||||
# Load custom icon
|
||||
self.icon_id = idaapi.load_custom_icon(data=MyChooserForm.icon_data)
|
||||
if self.icon_id == 0:
|
||||
raise RuntimeError("Failed to load icon data!")
|
||||
|
||||
self.main_current_index = -1
|
||||
self.EChMain = MainChooserClass("MainChooser", self.icon_id)
|
||||
self.EChAux = AuxChooserClass("AuxChooser", self.icon_id)
|
||||
|
||||
# Link the form to the EChooser
|
||||
self.EChMain.form = self
|
||||
self.EChAux.form = self
|
||||
|
||||
Form.__init__(self, r"""STARTITEM 0
|
||||
%s
|
||||
|
||||
{FormChangeCb}
|
||||
Select an item in the main chooser:
|
||||
|
||||
<Main chooser:{ctrlMainChooser}><Auxiliar chooser (multi):{ctrlAuxChooser}>
|
||||
|
||||
|
||||
<Selection:{ctrlSelectionEdit}>
|
||||
|
||||
""" % self.TITLE_PFX, {
|
||||
'ctrlSelectionEdit' : Form.StringInput(),
|
||||
'FormChangeCb' : Form.FormChangeCb(self.OnFormChange),
|
||||
'ctrlMainChooser' : Form.EmbeddedChooserControl(self.EChMain),
|
||||
'ctrlAuxChooser' : Form.EmbeddedChooserControl(self.EChAux),
|
||||
})
|
||||
|
||||
# Add an action to the popup menu of the main chooser
|
||||
class Hooks(idaapi.UI_Hooks):
|
||||
def __init__(self, form):
|
||||
idaapi.UI_Hooks.__init__(self)
|
||||
self.form = form
|
||||
|
||||
def finish_populating_widget_popup(self, widget, popup):
|
||||
# ids are assigned alphabetically by name
|
||||
# so the id of the MainChooser is 3
|
||||
if idaapi.get_widget_type(widget) == idaapi.BWN_CHOOSER \
|
||||
and idaapi.get_widget_title(widget) == \
|
||||
MyChooserForm.TITLE_PFX + ":3":
|
||||
actdesc = idaapi.action_desc_t(
|
||||
None,
|
||||
"Test",
|
||||
TestActionHandler(self.form.EChMain),
|
||||
"Ctrl-K", # shortcut
|
||||
None, # tooltip
|
||||
self.form.icon_id)
|
||||
idaapi.attach_dynamic_action_to_popup(
|
||||
widget,
|
||||
popup,
|
||||
actdesc)
|
||||
self.hooks = Hooks(self)
|
||||
self.hooks.hook()
|
||||
|
||||
|
||||
def refresh_selection_edit(self):
|
||||
if self.main_current_index == -1:
|
||||
s = "No selection in the main chooser"
|
||||
else:
|
||||
s = "Main %d" % (self.main_current_index + 1)
|
||||
|
||||
# Get selection in the aux chooser
|
||||
sel = self.GetControlValue(self.ctrlAuxChooser)
|
||||
if sel:
|
||||
s = "%s - Aux item(s): %s" % (s, ",".join(str(x + 1) for x in sel))
|
||||
|
||||
# Update string input
|
||||
self.SetControlValue(self.ctrlSelectionEdit, s)
|
||||
|
||||
|
||||
def OnFormChange(self, fid):
|
||||
if fid == -1:
|
||||
print("initializing")
|
||||
self.refresh_selection_edit()
|
||||
|
||||
elif fid == -2:
|
||||
print("terminating");
|
||||
|
||||
elif fid == self.ctrlMainChooser.id:
|
||||
print("main chooser selection change");
|
||||
l = self.GetControlValue(self.ctrlMainChooser);
|
||||
self.main_current_index = l[0] if l else -1
|
||||
|
||||
# Refresh auxiliar chooser
|
||||
self.RefreshField(self.ctrlAuxChooser)
|
||||
self.refresh_selection_edit()
|
||||
|
||||
elif fid == self.ctrlAuxChooser.id:
|
||||
self.refresh_selection_edit()
|
||||
|
||||
elif fid == self.ctrlSelectionEdit.id:
|
||||
pass
|
||||
else:
|
||||
print("unknown id %d" % fid)
|
||||
|
||||
return 1
|
||||
|
||||
def main():
|
||||
global f
|
||||
f = MyChooserForm()
|
||||
try:
|
||||
f.Compile()
|
||||
r = f.Execute()
|
||||
print("Execute returned: %d" % r)
|
||||
f.Free()
|
||||
except Exception as e:
|
||||
print("Failed to show form: %s" % str(e))
|
||||
|
||||
if __name__=='__main__':
|
||||
main()
|
||||
11
idasdk76/plugins/formchooser/makefile
Normal file
11
idasdk76/plugins/formchooser/makefile
Normal file
@@ -0,0 +1,11 @@
|
||||
PROC=formchooser
|
||||
|
||||
include ../plugin.mak
|
||||
|
||||
# MAKEDEP dependency list ------------------
|
||||
$(F)formchooser$(O): $(I)bitrange.hpp $(I)bytes.hpp $(I)config.hpp \
|
||||
$(I)fpro.h $(I)funcs.hpp $(I)ida.hpp $(I)idp.hpp \
|
||||
$(I)ieee.h $(I)kernwin.hpp $(I)lines.hpp $(I)llong.hpp \
|
||||
$(I)loader.hpp $(I)nalt.hpp $(I)netnode.hpp $(I)pro.h \
|
||||
$(I)range.hpp $(I)segment.hpp $(I)ua.hpp $(I)xref.hpp \
|
||||
formchooser.cpp
|
||||
BIN
idasdk76/plugins/formchooser/smile.png
Normal file
BIN
idasdk76/plugins/formchooser/smile.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 182 B |
174
idasdk76/plugins/formsample/formsample.cpp
Normal file
174
idasdk76/plugins/formsample/formsample.cpp
Normal file
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
* This plugin demonstrates how to use complex forms.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <ida.hpp>
|
||||
#include <idp.hpp>
|
||||
#include <loader.hpp>
|
||||
#include <kernwin.hpp>
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
struct plugin_ctx_t : public plugmod_t
|
||||
{
|
||||
virtual bool idaapi run(size_t) override;
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static int idaapi btn_cb(int, form_actions_t &)
|
||||
{
|
||||
warning("button pressed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static int idaapi modcb(int fid, form_actions_t &fa)
|
||||
{
|
||||
switch ( fid )
|
||||
{
|
||||
case CB_INIT:
|
||||
msg("initializing\n");
|
||||
break;
|
||||
case CB_YES:
|
||||
msg("terminating\n");
|
||||
break;
|
||||
case 5: // operand
|
||||
msg("changed operand\n");
|
||||
break;
|
||||
case 6: // check
|
||||
msg("changed check\n");
|
||||
break;
|
||||
case 7: // button
|
||||
msg("changed button\n");
|
||||
break;
|
||||
case 8: // color button
|
||||
msg("changed color button\n");
|
||||
break;
|
||||
default:
|
||||
msg("unknown id %d\n", fid);
|
||||
break;
|
||||
}
|
||||
|
||||
bool is_gui = is_idaq();
|
||||
|
||||
qstring buf0;
|
||||
if ( !fa.get_string_value(5, &buf0) )
|
||||
INTERR(30145);
|
||||
|
||||
if ( buf0 == "on" )
|
||||
fa.enable_field(12, true);
|
||||
|
||||
if ( buf0 == "off" )
|
||||
fa.enable_field(12, false);
|
||||
|
||||
ushort buf1;
|
||||
if ( !fa.get_cbgroup_value(12, &buf1) )
|
||||
INTERR(30146);
|
||||
|
||||
fa.show_field(7, (buf1 & 1) != 0);
|
||||
fa.enable_field(8, (buf1 & 2) != 0);
|
||||
|
||||
|
||||
ushort c13;
|
||||
if ( !fa.get_checkbox_value(13, &c13) )
|
||||
INTERR(30147);
|
||||
fa.enable_field(10, c13 != 0);
|
||||
|
||||
ushort c14;
|
||||
if ( !fa.get_checkbox_value(14, &c14) )
|
||||
INTERR(30148);
|
||||
fa.enable_field(5, c14 != 0);
|
||||
|
||||
ushort c15;
|
||||
if ( !fa.get_checkbox_value(15, &c15) )
|
||||
INTERR(30149);
|
||||
|
||||
if ( (buf1 & 8) != 0 )
|
||||
{
|
||||
sval_t x, y, w, h;
|
||||
fa.get_signed_value(4, &x);
|
||||
fa.get_signed_value(3, &y);
|
||||
fa.get_signed_value(2, &w);
|
||||
fa.get_signed_value(1, &h);
|
||||
fa.move_field(5, x, y, w, h);
|
||||
if ( x != -1 && c15 )
|
||||
fa.move_field(-5, x-7, y, w, h);
|
||||
}
|
||||
|
||||
// get_field_value() for buttons must return false always
|
||||
if ( fa._get_field_value(7, NULL) )
|
||||
INTERR(30150);
|
||||
|
||||
bgcolor_t bgc = -1;
|
||||
if ( is_gui && !fa.get_color_value(8, &bgc) )
|
||||
INTERR(30151);
|
||||
msg(" op=%s change=%x color=%x\n", buf0.c_str(), buf1, bgc);
|
||||
|
||||
fa.set_label_value(9, buf0.c_str());
|
||||
return 1;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
bool idaapi plugin_ctx_t::run(size_t)
|
||||
{
|
||||
static const char form[] =
|
||||
"@0:477[]\n"
|
||||
"Manual operand\n"
|
||||
"\n"
|
||||
"%/Enter alternate string for the %9X operand\n"
|
||||
"\n"
|
||||
" <~O~perand:q5:100:40::>\n"
|
||||
" <~X~:D4:100:10::>\n"
|
||||
" <~Y~:D3:100:10::>\n"
|
||||
" <~W~:D2:100:10::>\n"
|
||||
" <~H~:D1:100:10::>\n"
|
||||
"\n"
|
||||
" <S~h~ow Button:C10>\n"
|
||||
" <~E~nable color Button:C11>\n"
|
||||
" <~E~nable C10:C13>\n"
|
||||
" <~S~et operand bounds:C6>\n"
|
||||
" <Enable operand:C14>\n"
|
||||
" <Move label:C15>12>\n"
|
||||
"\n"
|
||||
" <~B~utton:B7:0:::> <~C~olor button:K8::::>\n"
|
||||
"\n"
|
||||
"\n";
|
||||
qstring buf("original");
|
||||
ushort check = 0x12;
|
||||
bgcolor_t bgc = 0x556677;
|
||||
uval_t x = -1;
|
||||
uval_t y = -1;
|
||||
uval_t w = -1;
|
||||
uval_t h = -1;
|
||||
CASSERT(IS_FORMCHGCB_T(modcb));
|
||||
CASSERT(IS_QSTRING(buf));
|
||||
if ( ask_form(form, modcb, buf.c_str(), &buf, &x, &y, &w, &h, &check, btn_cb, &bgc) > 0 )
|
||||
{
|
||||
msg("operand: %s\n", buf.c_str());
|
||||
msg("check = %d\n", check);
|
||||
msg("dim = %a %a %a %a\n", x, y, w, h);
|
||||
msg("bgc = %x\n", bgc);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static plugmod_t *idaapi init()
|
||||
{
|
||||
return new plugin_ctx_t;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
plugin_t PLUGIN =
|
||||
{
|
||||
IDP_INTERFACE_VERSION,
|
||||
PLUGIN_UNL // Unload the plugin immediately after calling 'run'
|
||||
| PLUGIN_MULTI, // The plugin can work with multiple idbs in parallel
|
||||
init, // initialize
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr, // long comment about the plugin
|
||||
nullptr, // multiline help about the plugin
|
||||
"ask_form sample", // the preferred short name of the plugin
|
||||
nullptr, // the preferred hotkey to run the plugin
|
||||
};
|
||||
11
idasdk76/plugins/formsample/makefile
Normal file
11
idasdk76/plugins/formsample/makefile
Normal file
@@ -0,0 +1,11 @@
|
||||
PROC=formsample
|
||||
|
||||
include ../plugin.mak
|
||||
|
||||
# MAKEDEP dependency list ------------------
|
||||
$(F)formsample$(O): $(I)bitrange.hpp $(I)bytes.hpp $(I)config.hpp \
|
||||
$(I)fpro.h $(I)funcs.hpp $(I)ida.hpp $(I)idp.hpp \
|
||||
$(I)ieee.h $(I)kernwin.hpp $(I)lines.hpp $(I)llong.hpp \
|
||||
$(I)loader.hpp $(I)nalt.hpp $(I)netnode.hpp $(I)pro.h \
|
||||
$(I)range.hpp $(I)segment.hpp $(I)ua.hpp $(I)xref.hpp \
|
||||
formsample.cpp
|
||||
226
idasdk76/plugins/funclist/funclist.cpp
Normal file
226
idasdk76/plugins/funclist/funclist.cpp
Normal file
@@ -0,0 +1,226 @@
|
||||
/*
|
||||
* This is a sample plugin module
|
||||
*
|
||||
* It demonstrates how to get the the entry point prototypes
|
||||
*
|
||||
*/
|
||||
|
||||
#include <ida.hpp>
|
||||
#include <idp.hpp>
|
||||
#include <auto.hpp>
|
||||
#include <entry.hpp>
|
||||
#include <bytes.hpp>
|
||||
#include <loader.hpp>
|
||||
#include <kernwin.hpp>
|
||||
#include <typeinf.hpp>
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
struct plugin_ctx_t : public plugmod_t
|
||||
{
|
||||
virtual bool idaapi run(size_t) override;
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// non-modal entry point chooser
|
||||
struct entry_chooser_t : public chooser_t
|
||||
{
|
||||
protected:
|
||||
struct item_t
|
||||
{
|
||||
ea_t ea;
|
||||
qstring decl;
|
||||
int ord;
|
||||
uint32 argsize;
|
||||
};
|
||||
// remember the information about an entry point in this qvector
|
||||
qvector<item_t> list;
|
||||
|
||||
static const int widths_[];
|
||||
static const char *const header_[];
|
||||
|
||||
public:
|
||||
// this object must be allocated using `new`
|
||||
entry_chooser_t();
|
||||
|
||||
// function that is used to decide whether a new chooser should be opened
|
||||
// or we can use the existing one.
|
||||
// There should be the only window as the entry points data are static.
|
||||
virtual const void *get_obj_id(size_t *len) const override { *len = 1; return ""; }
|
||||
|
||||
// function that returns number of lines in the list
|
||||
virtual size_t idaapi get_count() const override { return list.size(); }
|
||||
|
||||
// function that generates the list line
|
||||
virtual void idaapi get_row(
|
||||
qstrvec_t *cols,
|
||||
int *icon_,
|
||||
chooser_item_attrs_t *attrs,
|
||||
size_t n) const override;
|
||||
|
||||
// function that is called when the user hits Enter
|
||||
virtual cbret_t idaapi enter(size_t n) override
|
||||
{
|
||||
if ( n < list.size() )
|
||||
jumpto(list[n].ea);
|
||||
return cbret_t(); // nothing changed
|
||||
}
|
||||
|
||||
// function that is called when the chooser is initialized
|
||||
virtual bool idaapi init() override
|
||||
{
|
||||
// rebuild the list
|
||||
list.clear();
|
||||
size_t n = get_entry_qty();
|
||||
// gather information about the entry points
|
||||
for ( size_t i = 0; i < n; ++i )
|
||||
{
|
||||
asize_t ord = get_entry_ordinal(int(i));
|
||||
ea_t ea = get_entry(ord);
|
||||
if ( ord == ea )
|
||||
continue;
|
||||
tinfo_t type;
|
||||
qstring decl;
|
||||
qstring long_name;
|
||||
qstring true_name;
|
||||
asize_t argsize = 0;
|
||||
qstring entry_name;
|
||||
get_entry_name(&entry_name, ord);
|
||||
if ( get_tinfo(&type, ea) && type.print(&decl, entry_name.c_str()) )
|
||||
{
|
||||
// found type info, calc the size of arguments
|
||||
func_type_data_t fi;
|
||||
if ( type.get_func_details(&fi) && !fi.empty() )
|
||||
{
|
||||
for ( int k=0; k < fi.size(); k++ )
|
||||
{
|
||||
int s1 = fi[k].type.get_size();
|
||||
uchar szi = inf_get_cc_size_i();
|
||||
s1 = qmax(s1, szi);
|
||||
argsize += s1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ( get_long_name(&long_name, ea) > 0
|
||||
&& get_name(&true_name, ea, GN_NOT_DUMMY) > 0
|
||||
&& long_name != true_name )
|
||||
{
|
||||
// found mangled name
|
||||
}
|
||||
else
|
||||
{
|
||||
// found nothing, just show the name
|
||||
if ( get_visible_name(&decl, ea) <= 0 )
|
||||
continue;
|
||||
}
|
||||
if ( argsize == 0 )
|
||||
{
|
||||
func_t *pfn = get_func(ea);
|
||||
if ( pfn != NULL )
|
||||
argsize = pfn->argsize;
|
||||
}
|
||||
item_t x;
|
||||
x.ord = ord;
|
||||
x.ea = ea;
|
||||
x.decl.swap(decl);
|
||||
x.argsize = uint32(argsize);
|
||||
list.push_back(x);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// function that is called when the user wants to refresh the chooser
|
||||
virtual cbret_t idaapi refresh(ssize_t n) override
|
||||
{
|
||||
init();
|
||||
if ( n < 0 )
|
||||
return NO_SELECTION;
|
||||
return adjust_last_item(n); // try to preserve the cursor
|
||||
}
|
||||
};
|
||||
DECLARE_TYPE_AS_MOVABLE(entry_chooser_t::item_t);
|
||||
|
||||
// column widths
|
||||
const int entry_chooser_t::widths_[] =
|
||||
{
|
||||
CHCOL_DEC | 4, // Ordinal
|
||||
CHCOL_HEX | 8, // Address
|
||||
CHCOL_HEX | 6, // ArgSize
|
||||
70, // Declaration
|
||||
};
|
||||
// column headers
|
||||
const char *const entry_chooser_t::header_[] =
|
||||
{
|
||||
"Ordinal", // 0
|
||||
"Address", // 1
|
||||
"ArgSize", // 2
|
||||
"Declaration", // 3
|
||||
};
|
||||
|
||||
inline entry_chooser_t::entry_chooser_t()
|
||||
: chooser_t(CH_CAN_REFRESH, // user can refresh the chooser using Ctrl-U
|
||||
qnumber(widths_), widths_, header_,
|
||||
"Exported functions"),
|
||||
list()
|
||||
{
|
||||
CASSERT(qnumber(widths_) == qnumber(header_));
|
||||
}
|
||||
|
||||
void idaapi entry_chooser_t::get_row(
|
||||
qstrvec_t *cols_,
|
||||
int *,
|
||||
chooser_item_attrs_t *,
|
||||
size_t n) const
|
||||
{
|
||||
// assert: n < list.size()
|
||||
const item_t &item = list[n];
|
||||
|
||||
// generate the line
|
||||
qstrvec_t &cols = *cols_;
|
||||
cols[0].sprnt("%d", item.ord);
|
||||
cols[1].sprnt("%08a", item.ea);
|
||||
if ( item.argsize != 0 )
|
||||
cols[2].sprnt("%04x", item.argsize);
|
||||
cols[3] = item.decl;
|
||||
CASSERT(qnumber(header_) == 4);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
bool idaapi plugin_ctx_t::run(size_t)
|
||||
{
|
||||
if ( !auto_is_ok()
|
||||
&& ask_yn(ASKBTN_NO,
|
||||
"HIDECANCEL\n"
|
||||
"The autoanalysis has not finished yet.\n"
|
||||
"The result might be incomplete.\n"
|
||||
"Do you want to continue?") < ASKBTN_YES )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// open the window
|
||||
entry_chooser_t *ch = new entry_chooser_t();
|
||||
ch->choose();
|
||||
return true; //-V773
|
||||
} //lint !e429 'ch' has not been freed or returned
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static plugmod_t *idaapi init()
|
||||
{
|
||||
if ( get_entry_qty() == 0 )
|
||||
return nullptr;
|
||||
return new plugin_ctx_t;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
plugin_t PLUGIN =
|
||||
{
|
||||
IDP_INTERFACE_VERSION,
|
||||
PLUGIN_MULTI, // The plugin can work with multiple idbs in parallel
|
||||
init, // initialize
|
||||
nullptr,
|
||||
nullptr,
|
||||
"Generate list of exported function prototypes",
|
||||
"Generate list of exported function prototypes",
|
||||
"List of exported functions",
|
||||
"Ctrl-F11",
|
||||
};
|
||||
12
idasdk76/plugins/funclist/makefile
Normal file
12
idasdk76/plugins/funclist/makefile
Normal file
@@ -0,0 +1,12 @@
|
||||
PROC=funclist
|
||||
|
||||
include ../plugin.mak
|
||||
|
||||
# MAKEDEP dependency list ------------------
|
||||
$(F)funclist$(O): $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
|
||||
$(I)config.hpp $(I)entry.hpp $(I)fpro.h $(I)funcs.hpp \
|
||||
$(I)ida.hpp $(I)idp.hpp $(I)ieee.h $(I)kernwin.hpp \
|
||||
$(I)lines.hpp $(I)llong.hpp $(I)loader.hpp $(I)nalt.hpp \
|
||||
$(I)name.hpp $(I)netnode.hpp $(I)pro.h $(I)range.hpp \
|
||||
$(I)segment.hpp $(I)typeinf.hpp $(I)ua.hpp $(I)xref.hpp \
|
||||
funclist.cpp
|
||||
86
idasdk76/plugins/getlines/getlines.cpp
Normal file
86
idasdk76/plugins/getlines/getlines.cpp
Normal file
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* This is a sample plugin module
|
||||
*
|
||||
* It demonstrates how to get the disassembly lines for one address
|
||||
*
|
||||
*/
|
||||
|
||||
#include <ida.hpp>
|
||||
#include <idp.hpp>
|
||||
#include <bytes.hpp>
|
||||
#include <loader.hpp>
|
||||
#include <kernwin.hpp>
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
struct plugin_ctx_t : public plugmod_t
|
||||
{
|
||||
virtual bool idaapi run(size_t) override;
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
bool idaapi plugin_ctx_t::run(size_t)
|
||||
{
|
||||
ea_t ea = get_screen_ea();
|
||||
if ( ask_addr(&ea, "Please enter the disassembly address")
|
||||
&& is_mapped(ea) ) // address belongs to disassembly
|
||||
{
|
||||
int flags = calc_default_idaplace_flags();
|
||||
linearray_t ln(&flags);
|
||||
idaplace_t pl;
|
||||
pl.ea = ea;
|
||||
pl.lnnum = 0;
|
||||
ln.set_place(&pl);
|
||||
msg("printing disassembly lines:\n");
|
||||
int n = ln.get_linecnt(); // how many lines for this address?
|
||||
for ( int i=0; i < n; i++ ) // process all of them
|
||||
{
|
||||
qstring buf;
|
||||
tag_remove(&buf, *ln.down()); // get line and remove color codes
|
||||
msg("%d: %s\n", i, buf.c_str()); // display it on the message window
|
||||
}
|
||||
msg("total %d lines\n", n);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static plugmod_t *idaapi init()
|
||||
{
|
||||
return new plugin_ctx_t;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static const char comment[] = "Generate disassembly lines for one address";
|
||||
static const char help[] = "Generate disassembly lines for one address\n";
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// This is the preferred name of the plugin module in the menu system
|
||||
// The preferred name may be overridden in plugins.cfg file
|
||||
|
||||
static const char wanted_name[] = "Disassembly lines sample";
|
||||
|
||||
|
||||
// This is the preferred hotkey for the plugin module
|
||||
// The preferred hotkey may be overridden in plugins.cfg file
|
||||
|
||||
static const char wanted_hotkey[] = "";
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// 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
|
||||
help, // multiline help about the plugin
|
||||
wanted_name, // the preferred short name of the plugin
|
||||
wanted_hotkey // the preferred hotkey to run the plugin
|
||||
};
|
||||
11
idasdk76/plugins/getlines/makefile
Normal file
11
idasdk76/plugins/getlines/makefile
Normal file
@@ -0,0 +1,11 @@
|
||||
PROC=getlines
|
||||
|
||||
include ../plugin.mak
|
||||
|
||||
# MAKEDEP dependency list ------------------
|
||||
$(F)getlines$(O): $(I)bitrange.hpp $(I)bytes.hpp $(I)config.hpp $(I)fpro.h \
|
||||
$(I)funcs.hpp $(I)ida.hpp $(I)idp.hpp $(I)ieee.h \
|
||||
$(I)kernwin.hpp $(I)lines.hpp $(I)llong.hpp \
|
||||
$(I)loader.hpp $(I)nalt.hpp $(I)netnode.hpp $(I)pro.h \
|
||||
$(I)range.hpp $(I)segment.hpp $(I)ua.hpp $(I)xref.hpp \
|
||||
getlines.cpp
|
||||
38
idasdk76/plugins/hello/hello.cpp
Normal file
38
idasdk76/plugins/hello/hello.cpp
Normal file
@@ -0,0 +1,38 @@
|
||||
#include <ida.hpp>
|
||||
#include <idp.hpp>
|
||||
#include <loader.hpp>
|
||||
#include <kernwin.hpp>
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
struct plugin_ctx_t : public plugmod_t
|
||||
{
|
||||
virtual bool idaapi run(size_t) override;
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
bool idaapi plugin_ctx_t::run(size_t)
|
||||
{
|
||||
msg("Hello, world! (cpp)\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static plugmod_t *idaapi init()
|
||||
{
|
||||
return new plugin_ctx_t;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
plugin_t PLUGIN =
|
||||
{
|
||||
IDP_INTERFACE_VERSION,
|
||||
PLUGIN_UNL // Unload the plugin immediately after calling 'run'
|
||||
| PLUGIN_MULTI, // The plugin can work with multiple idbs in parallel
|
||||
init, // initialize
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr, // long comment about the plugin
|
||||
nullptr, // multiline help about the plugin
|
||||
"Hello, world", // the preferred short name of the plugin
|
||||
nullptr, // the preferred hotkey to run the plugin
|
||||
};
|
||||
30
idasdk76/plugins/hello/hello.idc
Normal file
30
idasdk76/plugins/hello/hello.idc
Normal file
@@ -0,0 +1,30 @@
|
||||
#include <idc.idc>
|
||||
|
||||
class myplugin_t
|
||||
{
|
||||
myplugin_t()
|
||||
{
|
||||
this.flags = 0;
|
||||
this.comment = "This is a comment";
|
||||
this.help = "This is help";
|
||||
this.wanted_name = "Sample IDC plugin";
|
||||
this.wanted_hotkey = "Alt-F6";
|
||||
}
|
||||
init()
|
||||
{
|
||||
return PLUGIN_OK;
|
||||
}
|
||||
run(arg)
|
||||
{
|
||||
msg("Hello world\n");
|
||||
return 0;
|
||||
}
|
||||
term()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
static PLUGIN_ENTRY()
|
||||
{
|
||||
return myplugin_t();
|
||||
}
|
||||
21
idasdk76/plugins/hello/hello.py
Normal file
21
idasdk76/plugins/hello/hello.py
Normal file
@@ -0,0 +1,21 @@
|
||||
import idaapi
|
||||
|
||||
class myplugin_t(idaapi.plugin_t):
|
||||
flags = idaapi.PLUGIN_UNL
|
||||
comment = "This is a comment"
|
||||
help = "This is help"
|
||||
wanted_name = "My Python plugin"
|
||||
wanted_hotkey = "Alt-F8"
|
||||
|
||||
def init(self):
|
||||
return idaapi.PLUGIN_OK
|
||||
|
||||
def run(self, arg):
|
||||
print "Hello world!"
|
||||
|
||||
def term(self):
|
||||
pass
|
||||
|
||||
def PLUGIN_ENTRY():
|
||||
return myplugin_t()
|
||||
|
||||
26
idasdk76/plugins/hello/makefile
Normal file
26
idasdk76/plugins/hello/makefile
Normal file
@@ -0,0 +1,26 @@
|
||||
PROC=hello
|
||||
|
||||
include ../plugin.mak
|
||||
|
||||
all: scripts
|
||||
|
||||
SCRIPTS := $(addprefix $(BIN_PATH),idchello.idc pyhello.py)
|
||||
|
||||
.PHONY: scripts
|
||||
scripts: $(SCRIPTS)
|
||||
|
||||
$(BIN_PATH)%.idc: %.idc
|
||||
$(CP) $? $@
|
||||
$(BIN_PATH)%.py: %.py
|
||||
$(CP) $? $@
|
||||
|
||||
uninstall::
|
||||
rm -rf $(SCRIPTS)
|
||||
|
||||
# MAKEDEP dependency list ------------------
|
||||
$(F)hello$(O) : $(I)bitrange.hpp $(I)bytes.hpp $(I)config.hpp $(I)fpro.h \
|
||||
$(I)funcs.hpp $(I)ida.hpp $(I)idp.hpp $(I)ieee.h \
|
||||
$(I)kernwin.hpp $(I)lines.hpp $(I)llong.hpp \
|
||||
$(I)loader.hpp $(I)nalt.hpp $(I)netnode.hpp $(I)pro.h \
|
||||
$(I)range.hpp $(I)segment.hpp $(I)ua.hpp $(I)xref.hpp \
|
||||
hello.cpp
|
||||
227
idasdk76/plugins/hexview/hexplace.cpp
Normal file
227
idasdk76/plugins/hexview/hexplace.cpp
Normal file
@@ -0,0 +1,227 @@
|
||||
//--------------------------------------------------------------------------
|
||||
// hex place methods
|
||||
|
||||
typedef hex_place_t hp_t;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Short information about the current location.
|
||||
// It will be displayed in the status line
|
||||
void ida_export hex_place_t__print(const hp_t *, qstring *, void *)
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Convert current location to 'uval_t'
|
||||
uval_t ida_export hex_place_t__touval(const hp_t *ths, void *)
|
||||
{
|
||||
return ths->n;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Make a copy
|
||||
place_t *ida_export hex_place_t__clone(const hp_t *ths)
|
||||
{
|
||||
return new hp_t(*ths);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Copy from another hex_place_t object
|
||||
void ida_export hex_place_t__copyfrom(hp_t *ths, const place_t *from)
|
||||
{
|
||||
hp_t *s = (hp_t *)from;
|
||||
ths->d = s->d;
|
||||
ths->n = s->n;
|
||||
ths->lnnum = s->lnnum;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Create a hex_place_t object at the specified address
|
||||
// with the specified data
|
||||
place_t *ida_export hex_place_t__makeplace(const hp_t *ths, void *, uval_t x, int lnnum)
|
||||
{
|
||||
hex_place_t *p = new hex_place_t();
|
||||
p->d = ths->d;
|
||||
p->n = x;
|
||||
p->lnnum = lnnum;
|
||||
return p;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
int ida_export hex_place_t__compare(const hp_t *ths, const place_t *t2)
|
||||
{
|
||||
hp_t *s = (hp_t *)t2;
|
||||
return compare(ths->n, s->n);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Compare two hex_place_t objects
|
||||
// Return -1, 0, 1
|
||||
int ida_export hex_place_t__compare2(const hp_t *ths, const place_t *t2, void *)
|
||||
{
|
||||
return hex_place_t__compare(ths, t2);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Check if the location data is correct and if not, adjust it
|
||||
void ida_export hex_place_t__adjust(hp_t *ths, void *)
|
||||
{
|
||||
if ( ths->n > ths->d->maxline() )
|
||||
{
|
||||
ths->n = 0;
|
||||
ths->lnnum = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Move to the previous location
|
||||
bool ida_export hex_place_t__prev(hp_t *ths, void *)
|
||||
{
|
||||
if ( ths->n == 0 )
|
||||
return false;
|
||||
ths->n--;
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Move to the next location
|
||||
bool ida_export hex_place_t__next(hp_t *ths, void *)
|
||||
{
|
||||
if ( ths->n >= ths->d->maxline() )
|
||||
return false;
|
||||
ths->n++;
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Are we at the beginning of the data?
|
||||
bool ida_export hex_place_t__beginning(const hp_t *ths, void *)
|
||||
{
|
||||
return ths->n == 0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Are we at the end of the data?
|
||||
bool ida_export hex_place_t__ending(const hp_t *ths, void *)
|
||||
{
|
||||
return ths->n == ths->d->maxline();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Generate text for the current location
|
||||
int ida_export hex_place_t__generate(
|
||||
const hp_t *ths,
|
||||
qstrvec_t *out,
|
||||
int *default_lnnum,
|
||||
color_t *,
|
||||
bgcolor_t *,
|
||||
void *,
|
||||
int maxsize)
|
||||
{
|
||||
int idx = ths->n;
|
||||
if ( idx > ths->d->maxline() || maxsize <= 0 )
|
||||
return 0;
|
||||
uint alignment = ths->d->alignment();
|
||||
uchar *data = (uchar *)qalloc(alignment);
|
||||
if ( !ths->d->read(alignment * ths->n, data, alignment) )
|
||||
{
|
||||
qfree(data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define HEX_ASCII_SEP 2
|
||||
size_t bufsize = 4 * alignment + HEX_ASCII_SEP + 20;
|
||||
char *str = (char *)qalloc(bufsize);
|
||||
if ( str == NULL )
|
||||
nomem("hexplace");
|
||||
str[0] = 0;
|
||||
|
||||
// add hex values
|
||||
static const char hexstr[] = "0123456789ABCDEF";
|
||||
size_t pos = qstrlen(str);
|
||||
for ( uint i = 0; i < alignment; i++ )
|
||||
{
|
||||
str[pos++] = ' ';
|
||||
uchar c = data[i];
|
||||
str[pos++] = hexstr[c >> 4];
|
||||
str[pos++] = hexstr[c & 0xF];
|
||||
}
|
||||
|
||||
memset(&str[pos], ' ', HEX_ASCII_SEP);
|
||||
pos += HEX_ASCII_SEP;
|
||||
|
||||
// add ascii values
|
||||
char *ptr = str + pos;
|
||||
char *end = str + bufsize;
|
||||
APPCHAR(ptr, end, COLOR_ON);
|
||||
APPCHAR(ptr, end, COLOR_NUMBER);
|
||||
for ( uint i = 0; i < alignment; i++ )
|
||||
APPCHAR(ptr, end, qisprint(data[i]) ? (char)data[i] : '.');
|
||||
APPCHAR(ptr, end, COLOR_OFF);
|
||||
APPCHAR(ptr, end, COLOR_NUMBER);
|
||||
APPZERO(ptr, end);
|
||||
|
||||
qfree(data);
|
||||
out->push_back(str);
|
||||
*default_lnnum = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
void ida_export hex_place_t__serialize(const hex_place_t *_this, bytevec_t *out)
|
||||
{
|
||||
place_t__serialize(_this, out);
|
||||
out->pack_ea(_this->n);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
bool ida_export hex_place_t__deserialize(hex_place_t *_this, const uchar **pptr, const uchar *end)
|
||||
{
|
||||
if ( !place_t__deserialize(_this, pptr, end) || *pptr >= end )
|
||||
return false;
|
||||
_this->n = unpack_ea(pptr, end);
|
||||
return true;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// this var is static because it is not database specific
|
||||
static int hex_place_id = -1;
|
||||
static const hex_place_t _template;
|
||||
void register_hex_place()
|
||||
{
|
||||
hex_place_id = register_place_class(&_template, PCF_MAKEPLACE_ALLOCATES, &PLUGIN);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
int ida_export hex_place_t__id(const hex_place_t *)
|
||||
{
|
||||
return hex_place_id;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
const char *ida_export hex_place_t__name(const hex_place_t *)
|
||||
{
|
||||
return "hexview:hex_place_t";
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
ea_t ida_export hex_place_t__toea(const hex_place_t *)
|
||||
{
|
||||
return BADADDR;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
place_t *ida_export hex_place_t__enter(const hex_place_t *, uint32 *)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
void ida_export hex_place_t__leave(const hex_place_t *, uint32)
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
bool ida_export hex_place_t__rebase(hex_place_t *, const segm_move_infos_t &)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
190
idasdk76/plugins/hexview/hexview.cpp
Normal file
190
idasdk76/plugins/hexview/hexview.cpp
Normal file
@@ -0,0 +1,190 @@
|
||||
//---------------------------------------------------------------------------
|
||||
// Hex view sample plugin
|
||||
|
||||
#include <ida.hpp>
|
||||
#include <idp.hpp>
|
||||
#include <loader.hpp>
|
||||
#include <kernwin.hpp>
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// hex data
|
||||
class hex_data_t : public plugmod_t, public event_listener_t
|
||||
{
|
||||
TWidget *cv = nullptr;
|
||||
TWidget *hexview = nullptr;
|
||||
|
||||
FILE *f = nullptr;
|
||||
uint64 sz = 10000;
|
||||
const uint align = 16;
|
||||
|
||||
public:
|
||||
|
||||
hex_data_t()
|
||||
{
|
||||
hook_event_listener(HT_VIEW, this);
|
||||
}
|
||||
~hex_data_t()
|
||||
{
|
||||
// listeners are uninstalled automatically
|
||||
// when the owner module is unloaded
|
||||
close();
|
||||
}
|
||||
|
||||
virtual bool idaapi run(size_t) override;
|
||||
virtual ssize_t idaapi on_event(ssize_t code, va_list va) override;
|
||||
|
||||
bool open(const char *fname)
|
||||
{
|
||||
close();
|
||||
f = qfopen(fname, "rb");
|
||||
if ( f == NULL )
|
||||
return false;
|
||||
// 64 bit functions could be used instead
|
||||
qfseek(f, 0, SEEK_END);
|
||||
sz = qftell(f);
|
||||
return true;
|
||||
}
|
||||
|
||||
void close()
|
||||
{
|
||||
cv = nullptr;
|
||||
hexview = nullptr;
|
||||
if ( f != nullptr )
|
||||
{
|
||||
qfclose(f);
|
||||
f = nullptr;
|
||||
sz = 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool read(uint64 pos, void *buf, size_t bufsize)
|
||||
{
|
||||
// 64 bit functions could be used instead
|
||||
if ( qfseek(f, pos, SEEK_SET) != 0 )
|
||||
return false;
|
||||
return qfread(f, buf, bufsize) == bufsize;
|
||||
}
|
||||
|
||||
uint64 size() const
|
||||
{
|
||||
return sz;
|
||||
}
|
||||
|
||||
int alignment() const
|
||||
{
|
||||
return align;
|
||||
}
|
||||
|
||||
uval_t pos_to_line(uint64 pos) const
|
||||
{
|
||||
return pos / align;
|
||||
}
|
||||
|
||||
uval_t maxline() const
|
||||
{
|
||||
return pos_to_line(sz - 1);
|
||||
}
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// hex place
|
||||
define_place_exported_functions(hex_place_t)
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
class hex_place_t : public place_t
|
||||
{
|
||||
public:
|
||||
hex_data_t *d;
|
||||
uval_t n;
|
||||
hex_place_t() : d(nullptr), n(0) { lnnum = 0; }
|
||||
hex_place_t(hex_data_t *_d, uint64 pos = 0) : d(_d)
|
||||
{
|
||||
n = d->pos_to_line(pos);
|
||||
lnnum = 0;
|
||||
}
|
||||
define_place_virtual_functions(hex_place_t)
|
||||
};
|
||||
#include "hexplace.cpp"
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
ssize_t idaapi hex_data_t::on_event(ssize_t code, va_list va)
|
||||
{
|
||||
switch ( code )
|
||||
{
|
||||
case ui_widget_invisible:
|
||||
{
|
||||
TWidget *w = va_arg(va, TWidget *);
|
||||
if ( w == hexview || w == cv )
|
||||
{
|
||||
close();
|
||||
unhook_event_listener(HT_UI, this);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Create a custom view window
|
||||
bool idaapi hex_data_t::run(size_t)
|
||||
{
|
||||
register_hex_place();
|
||||
|
||||
static const char title[] = "Sample hexview";
|
||||
TWidget *widget = find_widget(title);
|
||||
if ( widget != NULL )
|
||||
{
|
||||
warning("Hexview already open. Switching to it.");
|
||||
activate_widget(widget, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
// ask the user to select a file
|
||||
char *filename = ask_file(false, NULL, "Select a file to display...");
|
||||
if ( filename == NULL || filename[0] == 0 )
|
||||
return true;
|
||||
// open the file
|
||||
if ( !open(filename) )
|
||||
return true;
|
||||
|
||||
// create two place_t objects: for the minimal and maximal locations
|
||||
hex_place_t s1(this);
|
||||
hex_place_t s2(this, size() - 1);
|
||||
// create a custom viewer
|
||||
cv = create_custom_viewer(title, &s1, &s2, &s1, NULL, this, NULL, NULL);
|
||||
// create a code viewer container for the custom view
|
||||
hexview = create_code_viewer(cv);
|
||||
// set the radix and alignment for the offsets
|
||||
set_code_viewer_lines_radix(hexview, 16);
|
||||
set_code_viewer_lines_alignment(hexview, size() > 0xFFFFFFFF ? 16 : 8);
|
||||
// also set the ui event callback
|
||||
hook_event_listener(HT_UI, this);
|
||||
// finally display the form on the screen
|
||||
display_widget(hexview, WOPN_DP_TAB|WOPN_RESTORE);
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static plugmod_t *idaapi init()
|
||||
{
|
||||
return new hex_data_t;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// PLUGIN DESCRIPTION BLOCK
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
plugin_t PLUGIN =
|
||||
{
|
||||
IDP_INTERFACE_VERSION,
|
||||
PLUGIN_MULTI, // The plugin can work with multiple idbs in parallel
|
||||
init, // initialize
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr, // long comment about the plugin
|
||||
nullptr, // multiline help about the plugin
|
||||
"Sample hexview", // the preferred short name of the plugin
|
||||
nullptr, // the preferred hotkey to run the plugin
|
||||
};
|
||||
11
idasdk76/plugins/hexview/makefile
Normal file
11
idasdk76/plugins/hexview/makefile
Normal file
@@ -0,0 +1,11 @@
|
||||
PROC=hexview
|
||||
|
||||
include ../plugin.mak
|
||||
|
||||
# MAKEDEP dependency list ------------------
|
||||
$(F)hexview$(O) : $(I)bitrange.hpp $(I)bytes.hpp $(I)config.hpp $(I)fpro.h \
|
||||
$(I)funcs.hpp $(I)ida.hpp $(I)idp.hpp $(I)ieee.h \
|
||||
$(I)kernwin.hpp $(I)lines.hpp $(I)llong.hpp \
|
||||
$(I)loader.hpp $(I)nalt.hpp $(I)netnode.hpp $(I)pro.h \
|
||||
$(I)range.hpp $(I)segment.hpp $(I)ua.hpp $(I)xref.hpp \
|
||||
hexplace.cpp hexview.cpp
|
||||
193
idasdk76/plugins/highlighter/highlighter.cpp
Normal file
193
idasdk76/plugins/highlighter/highlighter.cpp
Normal file
@@ -0,0 +1,193 @@
|
||||
// Highlighter plugin v1.0
|
||||
// Highlights executed instructions
|
||||
|
||||
// This plugin will display a colored box at the executed instructions.
|
||||
// It will take into account only the instructions where the application
|
||||
// has been suspended.
|
||||
|
||||
// http://www.hexblog.com/2005/11/the_highlighter.html
|
||||
|
||||
// Copyright 2005 Ilfak Guilfanov, <ig@hexblog.com>
|
||||
|
||||
#include <ida.hpp>
|
||||
#include <idp.hpp>
|
||||
#include <dbg.hpp>
|
||||
#include <loader.hpp>
|
||||
#include <kernwin.hpp>
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
struct plugin_ctx_t;
|
||||
struct idd_post_events_t : public post_event_visitor_t
|
||||
{
|
||||
plugin_ctx_t &ctx;
|
||||
idd_post_events_t(plugin_ctx_t &_ctx) : ctx(_ctx) {}
|
||||
virtual ssize_t idaapi handle_post_event(
|
||||
ssize_t code,
|
||||
int notification_code,
|
||||
va_list va) override;
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
struct exec_prefix_t : public user_defined_prefix_t
|
||||
{
|
||||
static const int prefix_width = 1;
|
||||
|
||||
plugin_ctx_t &ctx;
|
||||
exec_prefix_t(plugin_ctx_t &_ctx)
|
||||
: user_defined_prefix_t(prefix_width, &_ctx), ctx(_ctx) {}
|
||||
|
||||
virtual void idaapi get_user_defined_prefix(
|
||||
qstring *out,
|
||||
ea_t ea,
|
||||
const insn_t &insn,
|
||||
int lnnum,
|
||||
int indent,
|
||||
const char *line) override;
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
typedef std::set<ea_t> easet_t;
|
||||
struct plugin_ctx_t : public plugmod_t, public event_listener_t
|
||||
{
|
||||
idd_post_events_t idd_post_events = idd_post_events_t(*this);
|
||||
|
||||
exec_prefix_t *exec_prefix = nullptr;
|
||||
|
||||
// List of executed addresses
|
||||
easet_t execset;
|
||||
|
||||
ea_t old_ea = BADADDR;
|
||||
int old_lnnum = 0;
|
||||
|
||||
plugin_ctx_t()
|
||||
{
|
||||
hook_event_listener(HT_DBG, this);
|
||||
}
|
||||
~plugin_ctx_t()
|
||||
{
|
||||
// listeners are uninstalled automatically
|
||||
// when the owner module is unloaded
|
||||
exec_prefix = nullptr; // make lint happy
|
||||
}
|
||||
|
||||
virtual bool idaapi run(size_t) override;
|
||||
virtual ssize_t idaapi on_event(ssize_t code, va_list va) override;
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// A sample how to generate user-defined line prefixes
|
||||
static const char highlight_prefix[] = { COLOR_INV, ' ', COLOR_INV, 0 };
|
||||
void idaapi exec_prefix_t::get_user_defined_prefix(
|
||||
qstring *buf,
|
||||
ea_t ea,
|
||||
const insn_t &,
|
||||
int lnnum,
|
||||
int indent,
|
||||
const char *line)
|
||||
{
|
||||
buf->qclear(); // empty prefix by default
|
||||
|
||||
// We want to display the prefix only the lines which
|
||||
// contain the instruction itself
|
||||
|
||||
if ( indent != -1 )
|
||||
return; // a directive
|
||||
if ( line[0] == '\0' )
|
||||
return; // empty line
|
||||
if ( tag_advance(line,1)[-1] == ASH.cmnt[0] )
|
||||
return; // comment line...
|
||||
|
||||
// We don't want the prefix to be printed again for other lines of the
|
||||
// same instruction/data. For that we remember the line number
|
||||
// and compare it before generating the prefix
|
||||
|
||||
if ( ctx.old_ea == ea && ctx.old_lnnum == lnnum )
|
||||
return;
|
||||
|
||||
if ( ctx.execset.find(ea) != ctx.execset.end() )
|
||||
*buf = highlight_prefix;
|
||||
|
||||
// Remember the address and line number we produced the line prefix for:
|
||||
ctx.old_ea = ea;
|
||||
ctx.old_lnnum = lnnum;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
ssize_t idaapi idd_post_events_t::handle_post_event(
|
||||
ssize_t retcode,
|
||||
int notification_code,
|
||||
va_list va)
|
||||
{
|
||||
switch ( notification_code )
|
||||
{
|
||||
case debugger_t::ev_get_debug_event:
|
||||
{
|
||||
gdecode_t *code = va_arg(va, gdecode_t *);
|
||||
debug_event_t *event = va_arg(va, debug_event_t *);
|
||||
if ( *code == GDE_ONE_EVENT ) // got an event?
|
||||
ctx.execset.insert(event->ea);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return retcode;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
bool idaapi plugin_ctx_t::run(size_t)
|
||||
{
|
||||
info("AUTOHIDE NONE\n"
|
||||
"This is the highlighter plugin.\n"
|
||||
"It highlights executed instructions if a debug event occurs at them.\n"
|
||||
"The plugins is fully automatic and has no parameters.\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
ssize_t idaapi plugin_ctx_t::on_event(ssize_t code, va_list /*va*/)
|
||||
{
|
||||
// We set our debug event handler at the beginning and remove it at the end
|
||||
// of a debug session
|
||||
switch ( code )
|
||||
{
|
||||
case dbg_process_start:
|
||||
case dbg_process_attach:
|
||||
exec_prefix = new exec_prefix_t(*this);
|
||||
register_post_event_visitor(HT_IDD, &idd_post_events, this);
|
||||
break;
|
||||
case dbg_process_exit:
|
||||
// do not unregister idd_post_events - it should be removed automatically
|
||||
delete exec_prefix;
|
||||
exec_prefix = nullptr;
|
||||
execset.clear();
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static plugmod_t *idaapi init()
|
||||
{
|
||||
return new plugin_ctx_t;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static const char wanted_name[] = "Highlighter";
|
||||
static const char wanted_hotkey[] = "";
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// PLUGIN DESCRIPTION BLOCK
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
plugin_t PLUGIN =
|
||||
{
|
||||
IDP_INTERFACE_VERSION,
|
||||
PLUGIN_MULTI, // The plugin can work with multiple idbs in parallel
|
||||
init, // initialize
|
||||
nullptr,
|
||||
nullptr,
|
||||
wanted_name, // long comment about the plugin
|
||||
wanted_name, // multiline help about the plugin
|
||||
wanted_name, // the preferred short name of the plugin
|
||||
wanted_hotkey, // the preferred hotkey to run the plugin
|
||||
};
|
||||
11
idasdk76/plugins/highlighter/makefile
Normal file
11
idasdk76/plugins/highlighter/makefile
Normal file
@@ -0,0 +1,11 @@
|
||||
PROC=highlighter
|
||||
|
||||
include ../plugin.mak
|
||||
|
||||
# MAKEDEP dependency list ------------------
|
||||
$(F)highlighter$(O): $(I)bitrange.hpp $(I)bytes.hpp $(I)config.hpp \
|
||||
$(I)dbg.hpp $(I)fpro.h $(I)funcs.hpp $(I)ida.hpp \
|
||||
$(I)idd.hpp $(I)idp.hpp $(I)ieee.h $(I)kernwin.hpp \
|
||||
$(I)lines.hpp $(I)llong.hpp $(I)loader.hpp $(I)nalt.hpp \
|
||||
$(I)netnode.hpp $(I)pro.h $(I)range.hpp $(I)segment.hpp \
|
||||
$(I)ua.hpp $(I)xref.hpp highlighter.cpp
|
||||
220
idasdk76/plugins/ht_output/ht_output.cpp
Normal file
220
idasdk76/plugins/ht_output/ht_output.cpp
Normal file
@@ -0,0 +1,220 @@
|
||||
/*
|
||||
* This is a sample plugin demonstrating receiving output window notification callbacks
|
||||
* and using of new output window functions: get_output_curline, get_output_cursor,
|
||||
* get_output_selected_text, add_output_popup
|
||||
*
|
||||
*/
|
||||
|
||||
#include <idp.hpp>
|
||||
#include <loader.hpp>
|
||||
#include <kernwin.hpp>
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
struct ht_output_plugin_t : public plugmod_t, public event_listener_t
|
||||
{
|
||||
form_actions_t *fa = nullptr;
|
||||
qstring selected_data;
|
||||
|
||||
virtual bool idaapi run(size_t arg) override;
|
||||
virtual ssize_t idaapi on_event(ssize_t code, va_list va) override;
|
||||
|
||||
void desc_notification(
|
||||
const char *notification_name) const;
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
AS_PRINTF(2, 3) static void form_msg(form_actions_t *fa, const char *format, ...)
|
||||
{
|
||||
textctrl_info_t ti;
|
||||
fa->get_text_value(1, &ti);
|
||||
va_list va;
|
||||
va_start(va, format);
|
||||
ti.text.cat_vsprnt(format, va);
|
||||
va_end(va);
|
||||
fa->set_text_value(1, &ti);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void ht_output_plugin_t::desc_notification(
|
||||
const char *notification_name) const
|
||||
{
|
||||
form_msg(fa, "Received notification from output window: \"%s\"\n",
|
||||
notification_name);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
struct printsel_ah_t : public action_handler_t
|
||||
{
|
||||
ht_output_plugin_t *plugmod;
|
||||
|
||||
printsel_ah_t(ht_output_plugin_t *_plgmod) : plugmod(_plgmod) {}
|
||||
|
||||
virtual int idaapi activate(action_activation_ctx_t *) override
|
||||
{
|
||||
form_msg(plugmod->fa,
|
||||
"User menu item is called for selection: \"%s\"\n",
|
||||
plugmod->selected_data.c_str());
|
||||
return 1;
|
||||
}
|
||||
|
||||
virtual action_state_t idaapi update(action_update_ctx_t *) override
|
||||
{
|
||||
return AST_ENABLE_ALWAYS;
|
||||
}
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Callback for ui notifications
|
||||
static ssize_t idaapi ui_callback(void *ud, int notification_code, va_list va)
|
||||
{
|
||||
switch ( notification_code )
|
||||
{
|
||||
// called when IDA is preparing a context menu for a view
|
||||
// Here dynamic context-depending user menu items can be added.
|
||||
case ui_populating_widget_popup:
|
||||
{
|
||||
TWidget *f = va_arg(va, TWidget *);
|
||||
if ( get_widget_type(f) == BWN_OUTPUT )
|
||||
{
|
||||
TPopupMenu *p = va_arg(va, TPopupMenu *);
|
||||
ht_output_plugin_t *plgmod = (ht_output_plugin_t *) ud;
|
||||
plgmod->selected_data.qclear();
|
||||
if ( get_output_selected_text(&plgmod->selected_data) )
|
||||
{
|
||||
action_desc_t desc = DYNACTION_DESC_LITERAL(
|
||||
"Print selection",
|
||||
new printsel_ah_t(plgmod),
|
||||
nullptr, nullptr, -1);
|
||||
attach_dynamic_action_to_popup(f, p, desc, nullptr, 0);
|
||||
}
|
||||
plgmod->desc_notification("msg_popup");
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Callback for view notifications
|
||||
ssize_t idaapi ht_output_plugin_t::on_event(
|
||||
ssize_t notification_code,
|
||||
va_list va)
|
||||
{
|
||||
switch ( notification_code )
|
||||
{
|
||||
case msg_activated:
|
||||
desc_notification("msg_activated");
|
||||
break;
|
||||
case msg_deactivated:
|
||||
desc_notification("msg_deactivated");
|
||||
break;
|
||||
case msg_keydown:
|
||||
{
|
||||
desc_notification("msg_keydown");
|
||||
int key = va_arg(va, int);
|
||||
int state = va_arg(va, int);
|
||||
form_msg(fa, "Parameters: Key:%d(\'%c\') State:%d\n", key, key, state);
|
||||
}
|
||||
break;
|
||||
case msg_click:
|
||||
case msg_dblclick:
|
||||
{
|
||||
desc_notification(notification_code == msg_click ? "msg_click" : "msg_dblclick");
|
||||
int px = va_arg(va, int);
|
||||
int py = va_arg(va, int);
|
||||
int state = va_arg(va, int);
|
||||
qstring buf;
|
||||
if ( get_output_curline(&buf, false) )
|
||||
form_msg(fa, "Clicked string: %s\n", buf.c_str());
|
||||
int cx,cy;
|
||||
get_output_cursor(&cx, &cy);
|
||||
msg("Parameters: x:%d, y:%d, state:%d\n", px, py, state);
|
||||
msg("Cursor position:(%d, %d)\n", cx, cy);
|
||||
}
|
||||
break;
|
||||
case msg_closed:
|
||||
desc_notification("msg_closed");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static plugmod_t *idaapi init()
|
||||
{
|
||||
return new ht_output_plugin_t;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// this callback is called when something happens in our editor form
|
||||
static int idaapi editor_modcb(int fid, form_actions_t &f_actions)
|
||||
{
|
||||
ht_output_plugin_t *plgmod = (ht_output_plugin_t *) f_actions.get_ud();
|
||||
if ( fid == CB_INIT ) // Initialization
|
||||
{
|
||||
/* set callback for output window notifications */
|
||||
hook_to_notification_point(HT_UI, ui_callback, plgmod);
|
||||
hook_event_listener(HT_OUTPUT, plgmod, plgmod);
|
||||
plgmod->fa = &f_actions;
|
||||
}
|
||||
else if ( fid == CB_CLOSE )
|
||||
{
|
||||
unhook_event_listener(HT_OUTPUT, plgmod);
|
||||
unhook_from_notification_point(HT_UI, ui_callback, plgmod);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
bool idaapi ht_output_plugin_t::run(size_t)
|
||||
{
|
||||
static const char formdef[] =
|
||||
"BUTTON NO NONE\n" // we do not want the standard buttons on the form
|
||||
"BUTTON YES NONE\n"
|
||||
"BUTTON CANCEL NONE\n"
|
||||
"Editor form\n" // the form title. it is also used to refer to the form later
|
||||
"\n"
|
||||
"%/%*" // placeholder for the 'editor_modcb' callback, and its userdata
|
||||
"<Text:t1:30:40:::>\n" // text edit control
|
||||
"\n";
|
||||
|
||||
// structure for text edit control
|
||||
textctrl_info_t ti;
|
||||
ti.cb = sizeof(textctrl_info_t);
|
||||
ti.text = "";
|
||||
|
||||
open_form(formdef, 0, editor_modcb, this, &ti);
|
||||
return true;
|
||||
}
|
||||
|
||||
static const char wanted_name[] = "HT_OUTPUT notifications handling example";
|
||||
static const char wanted_hotkey[] = "Ctrl-Alt-F11";
|
||||
//--------------------------------------------------------------------------
|
||||
static const char comment[] = "HT_OUTPUT notifications handling";
|
||||
static const char help[] =
|
||||
"This pluging demonstrates handling of output window\n"
|
||||
"notifications: Activation/Desactivation, adding\n"
|
||||
"popup menus, keyboard and mouse events, changing of current\n"
|
||||
"cursor position and closing of view\n";
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// PLUGIN DESCRIPTION BLOCK
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
plugin_t PLUGIN =
|
||||
{
|
||||
IDP_INTERFACE_VERSION,
|
||||
PLUGIN_MULTI, // plugin flags
|
||||
init, // initialize
|
||||
nullptr,
|
||||
nullptr,
|
||||
comment, // long comment about the plugin
|
||||
// it could appear in the status line
|
||||
// or as a hint
|
||||
|
||||
help, // multiline help about the plugin
|
||||
|
||||
wanted_name, // the preferred short name of the plugin
|
||||
wanted_hotkey // the preferred hotkey to run the plugin
|
||||
};
|
||||
11
idasdk76/plugins/ht_output/makefile
Normal file
11
idasdk76/plugins/ht_output/makefile
Normal file
@@ -0,0 +1,11 @@
|
||||
PROC=ht_output
|
||||
|
||||
include ../plugin.mak
|
||||
|
||||
# MAKEDEP dependency list ------------------
|
||||
$(F)ht_output$(O): $(I)bitrange.hpp $(I)bytes.hpp $(I)config.hpp \
|
||||
$(I)fpro.h $(I)funcs.hpp $(I)ida.hpp $(I)idp.hpp \
|
||||
$(I)ieee.h $(I)kernwin.hpp $(I)lines.hpp $(I)llong.hpp \
|
||||
$(I)loader.hpp $(I)nalt.hpp $(I)netnode.hpp $(I)pro.h \
|
||||
$(I)range.hpp $(I)segment.hpp $(I)ua.hpp $(I)xref.hpp \
|
||||
ht_output.cpp
|
||||
243
idasdk76/plugins/ht_view/ht_view.cpp
Normal file
243
idasdk76/plugins/ht_view/ht_view.cpp
Normal file
@@ -0,0 +1,243 @@
|
||||
/*
|
||||
* This is a sample plugin demonstrating usage of the view callbacks
|
||||
* and adding custom menu items to popup menus
|
||||
*
|
||||
*/
|
||||
|
||||
#include <ida.hpp>
|
||||
#include <idp.hpp>
|
||||
#include <loader.hpp>
|
||||
#include <kernwin.hpp>
|
||||
#include <bytes.hpp>
|
||||
#include <graph.hpp>
|
||||
|
||||
#define ACTION1_NAME "ht_view:Act1"
|
||||
#define ACTION2_NAME "ht_view:Act2"
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
struct ht_view_plugin_t : public plugmod_t, public event_listener_t
|
||||
{
|
||||
bool hooked = false;
|
||||
|
||||
ht_view_plugin_t();
|
||||
virtual ~ht_view_plugin_t();
|
||||
virtual bool idaapi run(size_t arg) override;
|
||||
virtual ssize_t idaapi on_event(ssize_t code, va_list va) override;
|
||||
|
||||
void desc_notification(
|
||||
const char *notification_name,
|
||||
TWidget *view) const;
|
||||
void desc_mouse_event(
|
||||
const view_mouse_event_t *event) const;
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Callback for ui notifications
|
||||
static ssize_t idaapi ui_callback(void *ud, int notification_code, va_list va)
|
||||
{
|
||||
switch ( notification_code )
|
||||
{
|
||||
// called when IDA is preparing a context menu for a view
|
||||
// Here dynamic context-depending user menu items can be added.
|
||||
case ui_populating_widget_popup:
|
||||
{
|
||||
TWidget *view = va_arg(va, TWidget *);
|
||||
if ( get_widget_type(view) == BWN_DISASM )
|
||||
{
|
||||
TPopupMenu *p = va_arg(va, TPopupMenu *);
|
||||
ht_view_plugin_t *plgmod = (ht_view_plugin_t *) ud;
|
||||
plgmod->desc_notification("view_popup", view);
|
||||
attach_action_to_popup(view, p, ACTION1_NAME);
|
||||
attach_action_to_popup(view, p, ACTION2_NAME);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
struct ahandler_t : public action_handler_t
|
||||
{
|
||||
bool first;
|
||||
ahandler_t(bool _first) : first(_first) {}
|
||||
virtual int idaapi activate(action_activation_ctx_t *) override
|
||||
{
|
||||
msg("User %s menu item is called\n", first ? "first" : "second");
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual action_state_t idaapi update(action_update_ctx_t *) override
|
||||
{
|
||||
return AST_ENABLE_ALWAYS;
|
||||
}
|
||||
};
|
||||
static ahandler_t ah1(true);
|
||||
static ahandler_t ah2(false);
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static plugmod_t *idaapi init()
|
||||
{
|
||||
return new ht_view_plugin_t;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
ht_view_plugin_t::ht_view_plugin_t()
|
||||
{
|
||||
// Register actions
|
||||
const action_desc_t actions[] =
|
||||
{
|
||||
#define ROW(name, label, handler) ACTION_DESC_LITERAL_PLUGMOD(name, label, handler, this, NULL, NULL, -1)
|
||||
ROW(ACTION1_NAME, "First ht_view's popup menu item", &ah1),
|
||||
ROW(ACTION2_NAME, "Second ht_view's popup menu item", &ah2),
|
||||
#undef ROW
|
||||
};
|
||||
|
||||
for ( size_t i = 0, n = qnumber(actions); i < n; ++i )
|
||||
register_action(actions[i]);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
ht_view_plugin_t::~ht_view_plugin_t()
|
||||
{
|
||||
unhook_from_notification_point(HT_UI, ui_callback, this);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
bool idaapi ht_view_plugin_t::run(size_t)
|
||||
{
|
||||
/* set callback for view notifications */
|
||||
if ( !hooked )
|
||||
{
|
||||
hook_event_listener(HT_VIEW, this);
|
||||
hook_to_notification_point(HT_UI, ui_callback, this);
|
||||
hooked = true;
|
||||
msg("HT_VIEW: installed view notification hook.\n");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
ssize_t idaapi ht_view_plugin_t::on_event(
|
||||
ssize_t notification_code,
|
||||
va_list va)
|
||||
{
|
||||
TWidget *view = va_arg(va, TWidget *);
|
||||
switch ( notification_code )
|
||||
{
|
||||
case view_activated:
|
||||
desc_notification("view_activated", view);
|
||||
break;
|
||||
case view_deactivated:
|
||||
desc_notification("view_deactivated", view);
|
||||
break;
|
||||
case view_keydown:
|
||||
{
|
||||
desc_notification("view_keydown", view);
|
||||
int key = va_arg(va, int);
|
||||
int state = va_arg(va, int);
|
||||
msg("Parameters: Key:%d(\'%c\') State:%d\n", key, key, state);
|
||||
}
|
||||
break;
|
||||
case view_click:
|
||||
case view_dblclick:
|
||||
{
|
||||
desc_notification(notification_code == view_click ? "view_click" : "view_dblclick", view);
|
||||
desc_mouse_event(va_arg(va, view_mouse_event_t*));
|
||||
int cx,cy;
|
||||
get_cursor(&cx, &cy);
|
||||
msg("Cursor position:(%d, %d)\n", cx, cy);
|
||||
}
|
||||
break;
|
||||
case view_curpos:
|
||||
{
|
||||
desc_notification("view_curpos", view);
|
||||
if ( is_idaview(view) )
|
||||
{
|
||||
char buf[MAXSTR];
|
||||
ea2str(buf, sizeof(buf), get_screen_ea());
|
||||
msg("New address: %s\n", buf);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case view_mouse_over:
|
||||
{
|
||||
desc_notification("view_mouse_over", view);
|
||||
desc_mouse_event(va_arg(va, view_mouse_event_t*));
|
||||
}
|
||||
break;
|
||||
case view_close:
|
||||
desc_notification("view_close", view);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
void ht_view_plugin_t::desc_notification(
|
||||
const char *notification_name,
|
||||
TWidget *view) const
|
||||
{
|
||||
qstring buffer;
|
||||
get_widget_title(&buffer, view);
|
||||
msg("Received notification from view %s: \"%s\"\n",
|
||||
buffer.c_str(),
|
||||
notification_name);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
void ht_view_plugin_t::desc_mouse_event(
|
||||
const view_mouse_event_t *event) const
|
||||
{
|
||||
int px = event->x;
|
||||
int py = event->y;
|
||||
int state = event->state;
|
||||
qstring over_txt;
|
||||
const selection_item_t *item = event->location.item;
|
||||
if ( event->rtype != TCCRT_FLAT && item != NULL )
|
||||
{
|
||||
if ( item->is_node )
|
||||
over_txt.sprnt("node %d", item->node);
|
||||
else
|
||||
over_txt.sprnt("edge %d -> %d", item->elp.e.src, item->elp.e.dst);
|
||||
}
|
||||
else
|
||||
{
|
||||
over_txt = "(nothing)";
|
||||
}
|
||||
msg("Parameters: x:%d, y:%d, state:%d, over:%s\n", px, py, state, over_txt.c_str());
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
static const char wanted_name[] = "HT_VIEW notification handling example";
|
||||
static const char wanted_hotkey[] = "";
|
||||
//--------------------------------------------------------------------------
|
||||
static const char comment[] = "HT_VIEW notification Handling";
|
||||
static const char help[] =
|
||||
"This pluging demonstrates handling of custom and IdaView\n"
|
||||
"notifications: Activation/Desactivation of views, adding\n"
|
||||
"popup menus, keyboard and mouse events, changing of current\n"
|
||||
"address and closing of view\n";
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// PLUGIN DESCRIPTION BLOCK
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
plugin_t PLUGIN =
|
||||
{
|
||||
IDP_INTERFACE_VERSION,
|
||||
PLUGIN_MULTI, // plugin flags
|
||||
init, // initialize
|
||||
nullptr,
|
||||
nullptr,
|
||||
comment, // long comment about the plugin
|
||||
// it could appear in the status line
|
||||
// or as a hint
|
||||
|
||||
help, // multiline help about the plugin
|
||||
|
||||
wanted_name, // the preferred short name of the plugin
|
||||
wanted_hotkey // the preferred hotkey to run the plugin
|
||||
};
|
||||
11
idasdk76/plugins/ht_view/makefile
Normal file
11
idasdk76/plugins/ht_view/makefile
Normal file
@@ -0,0 +1,11 @@
|
||||
PROC=ht_view
|
||||
|
||||
include ../plugin.mak
|
||||
|
||||
# MAKEDEP dependency list ------------------
|
||||
$(F)ht_view$(O) : $(I)bitrange.hpp $(I)bytes.hpp $(I)config.hpp $(I)fpro.h \
|
||||
$(I)funcs.hpp $(I)gdl.hpp $(I)graph.hpp $(I)ida.hpp \
|
||||
$(I)idp.hpp $(I)ieee.h $(I)kernwin.hpp $(I)lines.hpp \
|
||||
$(I)llong.hpp $(I)loader.hpp $(I)nalt.hpp \
|
||||
$(I)netnode.hpp $(I)pro.h $(I)range.hpp $(I)segment.hpp \
|
||||
$(I)ua.hpp $(I)xref.hpp ht_view.cpp
|
||||
70
idasdk76/plugins/makefile
Normal file
70
idasdk76/plugins/makefile
Normal file
@@ -0,0 +1,70 @@
|
||||
include ../allmake.mak
|
||||
|
||||
GOALS += plugins
|
||||
GOALS += samples
|
||||
ifeq ($(or $(IDAHOME),$(DEMO_OR_FREE)),)
|
||||
GOALS += examples
|
||||
endif
|
||||
.PHONY: $(GOALS)
|
||||
all: $(GOALS)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
PLUGINS += callee
|
||||
PLUGINS += callgraph
|
||||
PLUGINS += choose
|
||||
PLUGINS += findcrypt2
|
||||
PLUGINS += ht_output
|
||||
PLUGINS += ht_view
|
||||
PLUGINS += pdb
|
||||
PLUGINS += tracing_api
|
||||
PLUGINS += uiswitch
|
||||
PLUGINS-$(__NT__) += uunp
|
||||
PLUGINS += $(PLUGINS-1)
|
||||
plugins: $(PLUGINS)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
SAMPLES += custdata
|
||||
SAMPLES += custview
|
||||
SAMPLES += formchooser
|
||||
SAMPLES += formsample
|
||||
SAMPLES += funclist
|
||||
SAMPLES += getlines
|
||||
SAMPLES += hexview
|
||||
SAMPLES += mtsample
|
||||
SAMPLES += openform
|
||||
SAMPLES += procext
|
||||
SAMPLES += ugraph
|
||||
SAMPLES += ugraph3
|
||||
SAMPLES += vcsample
|
||||
samples: $(SAMPLES)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
# Note: examples are not installed in the plugins/ directory by default.
|
||||
# to install them there, run 'make' from the plugin subdirectory.
|
||||
# to uninstall the plugin afterwards, run 'make uninstall' from
|
||||
# the plugin subdirectory or 'make examples_uninstall' from the
|
||||
# 'plugins' directory.
|
||||
HAS_QT := $(call ls,$(QTDIR))
|
||||
EXAMPLES += ex_debidc
|
||||
EXAMPLES += ex_events1
|
||||
EXAMPLES += script_plg
|
||||
EXAMPLES-$(HAS_QT) += qproject
|
||||
EXAMPLES-$(HAS_QT) += qwindow
|
||||
# do not include ugraph2 in the samples because it is buggy:
|
||||
# in some cases it combines blocks in such a way that switching to
|
||||
# graph view becomes impossible
|
||||
EXAMPLES += ugraph2
|
||||
# the z80dbg plugin will conflict with functionality already submitted
|
||||
# to the z80 processor module, so we don't install it
|
||||
EXAMPLES += z80dbg
|
||||
EXAMPLES += $(EXAMPLES-1)
|
||||
examples: $(EXAMPLES)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
.PHONY: $(PLUGINS) $(SAMPLES) $(EXAMPLES)
|
||||
$(PLUGINS) $(SAMPLES) $(EXAMPLES):
|
||||
$(Q)$(MAKE) -C $@
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
clean::
|
||||
$(foreach dir,$(PLUGINS) $(SAMPLES) $(EXAMPLES),$(MAKE) -C $(dir) clean;)
|
||||
11
idasdk76/plugins/mtsample/makefile
Normal file
11
idasdk76/plugins/mtsample/makefile
Normal file
@@ -0,0 +1,11 @@
|
||||
PROC=mtsample
|
||||
|
||||
include ../plugin.mak
|
||||
|
||||
# MAKEDEP dependency list ------------------
|
||||
$(F)mtsample$(O): $(I)bitrange.hpp $(I)bytes.hpp $(I)config.hpp $(I)fpro.h \
|
||||
$(I)funcs.hpp $(I)ida.hpp $(I)idp.hpp $(I)ieee.h \
|
||||
$(I)kernwin.hpp $(I)lines.hpp $(I)llong.hpp \
|
||||
$(I)loader.hpp $(I)nalt.hpp $(I)netnode.hpp $(I)pro.h \
|
||||
$(I)range.hpp $(I)segment.hpp $(I)ua.hpp $(I)xref.hpp \
|
||||
mtsample.cpp
|
||||
137
idasdk76/plugins/mtsample/mtsample.cpp
Normal file
137
idasdk76/plugins/mtsample/mtsample.cpp
Normal file
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* This is a sample multi-threaded plugin module
|
||||
*
|
||||
* It creates 3 new threads. Each threads sleeps and prints a message in a loop
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef __NT__
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include <ida.hpp>
|
||||
#include <idp.hpp>
|
||||
#include <loader.hpp>
|
||||
#include <kernwin.hpp>
|
||||
|
||||
#ifdef __NT__
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
struct plugin_ctx_t : public plugmod_t
|
||||
{
|
||||
qthread_t children[10] = { nullptr };
|
||||
int nchilds = 0;
|
||||
|
||||
~plugin_ctx_t() { term(); }
|
||||
void term()
|
||||
{
|
||||
if ( nchilds > 0 )
|
||||
{
|
||||
msg("Killing all threads\n");
|
||||
for ( int i=0; i < nchilds; i++ )
|
||||
{
|
||||
qthread_kill(children[i]);
|
||||
qthread_join(children[i]);
|
||||
// cancel all pending requests from the killed thread
|
||||
cancel_thread_exec_requests(children[i]);
|
||||
qthread_free(children[i]);
|
||||
}
|
||||
msg("Killed all threads\n");
|
||||
nchilds = 0;
|
||||
}
|
||||
}
|
||||
virtual bool idaapi run(size_t) override;
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static void say_hello(size_t id, qthread_t tid, int cnt)
|
||||
{
|
||||
struct ida_local hello_t : public exec_request_t
|
||||
{
|
||||
uint64 nsecs;
|
||||
size_t id;
|
||||
qthread_t tid;
|
||||
int cnt;
|
||||
int idaapi execute(void) override
|
||||
{
|
||||
uint64 now = get_nsec_stamp();
|
||||
int64 delay = now - nsecs;
|
||||
msg("Hello %d from thread %" FMT_Z ". tid=%p. current tid=%p (delay=%" FMT_64 "d)\n",
|
||||
cnt, id, tid, qthread_self(), delay);
|
||||
return 0;
|
||||
}
|
||||
hello_t(size_t _id, qthread_t _tid, int _cnt) : id(_id), tid(_tid), cnt(_cnt)
|
||||
{
|
||||
nsecs = get_nsec_stamp();
|
||||
}
|
||||
};
|
||||
hello_t hi(id, tid, cnt);
|
||||
|
||||
int mff;
|
||||
switch ( id % 3 )
|
||||
{
|
||||
case 0: mff = MFF_FAST; break;
|
||||
case 1: mff = MFF_READ; break;
|
||||
default:
|
||||
case 2: mff = MFF_WRITE; break;
|
||||
}
|
||||
execute_sync(hi, mff);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static int idaapi thread_func(void *ud)
|
||||
{
|
||||
size_t id = (size_t)ud;
|
||||
qthread_t tid = qthread_self();
|
||||
int cnt = 0;
|
||||
srand(id ^ (size_t)tid);
|
||||
while ( true )
|
||||
{
|
||||
say_hello(id, tid, cnt++);
|
||||
int r = rand() % 1000;
|
||||
qsleep(r);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
bool idaapi plugin_ctx_t::run(size_t)
|
||||
{
|
||||
if ( nchilds == 0 )
|
||||
{
|
||||
children[nchilds] = qthread_create(thread_func, (void *)(ssize_t)nchilds); nchilds++;
|
||||
children[nchilds] = qthread_create(thread_func, (void *)(ssize_t)nchilds); nchilds++;
|
||||
children[nchilds] = qthread_create(thread_func, (void *)(ssize_t)nchilds); nchilds++;
|
||||
msg("Three new threads have been created. Main thread id %p\n", qthread_self());
|
||||
for ( int i=0; i < 5; i++ )
|
||||
say_hello(-1, 0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
term();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static plugmod_t *idaapi init()
|
||||
{
|
||||
return new plugin_ctx_t;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
plugin_t PLUGIN =
|
||||
{
|
||||
IDP_INTERFACE_VERSION,
|
||||
PLUGIN_MULTI, // The plugin can work with multiple idbs in parallel
|
||||
init, // initialize
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr, // long comment about the plugin
|
||||
nullptr, // multiline help about the plugin
|
||||
"Multi-threaded sample", // the preferred short name of the plugin
|
||||
nullptr, // the preferred hotkey to run the plugin
|
||||
};
|
||||
11
idasdk76/plugins/navcolor/makefile
Normal file
11
idasdk76/plugins/navcolor/makefile
Normal file
@@ -0,0 +1,11 @@
|
||||
PROC=navcolor
|
||||
|
||||
include ../plugin.mak
|
||||
|
||||
# MAKEDEP dependency list ------------------
|
||||
$(F)navcolor$(O): $(I)bitrange.hpp $(I)bytes.hpp $(I)config.hpp $(I)fpro.h \
|
||||
$(I)funcs.hpp $(I)ida.hpp $(I)idp.hpp $(I)ieee.h \
|
||||
$(I)kernwin.hpp $(I)lines.hpp $(I)llong.hpp \
|
||||
$(I)loader.hpp $(I)nalt.hpp $(I)netnode.hpp $(I)pro.h \
|
||||
$(I)range.hpp $(I)segment.hpp $(I)ua.hpp $(I)xref.hpp \
|
||||
navcolor.cpp
|
||||
93
idasdk76/plugins/navcolor/navcolor.cpp
Normal file
93
idasdk76/plugins/navcolor/navcolor.cpp
Normal file
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* This plugin demonstrates how to customize navigation band colors.
|
||||
* Launch the plugin like so:
|
||||
* - to install: ida_loader.load_and_run_plugin("navcolor", 1)
|
||||
* - to uninstall: ida_loader.load_and_run_plugin("navcolor", 0)
|
||||
*/
|
||||
|
||||
#include <ida.hpp>
|
||||
#include <idp.hpp>
|
||||
#include <loader.hpp>
|
||||
#include <kernwin.hpp>
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
struct plugin_ctx_t : public plugmod_t
|
||||
{
|
||||
nav_colorizer_t *old_col_fun = nullptr;
|
||||
void *old_col_ud = nullptr;
|
||||
bool installed = false;
|
||||
|
||||
//lint -esym(1540, plugin_ctx_t::old_col_fun, plugin_ctx_t::old_col_ud)
|
||||
~plugin_ctx_t()
|
||||
{
|
||||
// uninstall our callback for navigation band, otherwise ida will crash
|
||||
maybe_uninstall();
|
||||
}
|
||||
virtual bool idaapi run(size_t) override;
|
||||
|
||||
bool maybe_install();
|
||||
bool maybe_uninstall();
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
bool idaapi plugin_ctx_t::run(size_t code)
|
||||
{
|
||||
return code == 1 ? maybe_install() : maybe_uninstall();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Callback that calculates the pixel color given the address and the number of bytes
|
||||
static uint32 idaapi my_colorizer(ea_t ea, asize_t nbytes, void *ud)
|
||||
{
|
||||
plugin_ctx_t &ctx = *(plugin_ctx_t *)ud;
|
||||
// you are at your own here. just for the sake of illustrating how things work
|
||||
// we will invert all colors
|
||||
uint32 color = ctx.old_col_fun(ea, nbytes, ctx.old_col_ud);
|
||||
return ~color;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
bool plugin_ctx_t::maybe_install()
|
||||
{
|
||||
bool ok = !installed;
|
||||
if ( ok )
|
||||
{
|
||||
set_nav_colorizer(&old_col_fun, &old_col_ud, my_colorizer, this);
|
||||
installed = true;
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
bool plugin_ctx_t::maybe_uninstall()
|
||||
{
|
||||
bool ok = installed;
|
||||
if ( ok )
|
||||
{
|
||||
set_nav_colorizer(NULL, NULL, old_col_fun, old_col_ud);
|
||||
installed = false;
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// initialize the plugin
|
||||
static plugmod_t *idaapi init()
|
||||
{
|
||||
return new plugin_ctx_t;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
plugin_t PLUGIN =
|
||||
{
|
||||
IDP_INTERFACE_VERSION,
|
||||
PLUGIN_MULTI, // The plugin can work with multiple idbs in parallel
|
||||
init, // initialize
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr, // long comment about the plugin
|
||||
nullptr, // multiline help about the plugin
|
||||
"Modify navigation band colors",// the preferred short name of the plugin
|
||||
nullptr, // the preferred hotkey to run the plugin
|
||||
};
|
||||
11
idasdk76/plugins/openform/makefile
Normal file
11
idasdk76/plugins/openform/makefile
Normal file
@@ -0,0 +1,11 @@
|
||||
PROC=openform
|
||||
|
||||
include ../plugin.mak
|
||||
|
||||
# MAKEDEP dependency list ------------------
|
||||
$(F)openform$(O): $(I)bitrange.hpp $(I)bytes.hpp $(I)config.hpp $(I)fpro.h \
|
||||
$(I)funcs.hpp $(I)ida.hpp $(I)idp.hpp $(I)ieee.h \
|
||||
$(I)kernwin.hpp $(I)lines.hpp $(I)llong.hpp \
|
||||
$(I)loader.hpp $(I)nalt.hpp $(I)netnode.hpp $(I)pro.h \
|
||||
$(I)range.hpp $(I)segment.hpp $(I)ua.hpp $(I)xref.hpp \
|
||||
openform.cpp
|
||||
306
idasdk76/plugins/openform/openform.cpp
Normal file
306
idasdk76/plugins/openform/openform.cpp
Normal file
@@ -0,0 +1,306 @@
|
||||
/*
|
||||
* This plugin demonstrates how to use non modal forms.
|
||||
* It creates 2 windows on the screen:
|
||||
* - a window with 4 buttons: dock, undock, show, hide (CONTROL FORM)
|
||||
* - a window with a text edit control and a list control (EDITOR FORM)
|
||||
* The buttons of the first window can be used to manage the second window.
|
||||
* We will call the first window 'CONTROL FORM' and the second window 'EDITOR
|
||||
* FORM', just to be able to reference them easily.
|
||||
*/
|
||||
|
||||
#include <ida.hpp>
|
||||
#include <idp.hpp>
|
||||
#include <loader.hpp>
|
||||
#include <kernwin.hpp>
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// chooser (list view) items
|
||||
static const char *const names[] =
|
||||
{
|
||||
"Item one",
|
||||
"Item two",
|
||||
"Item three"
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
struct plugin_ctx_t : public plugmod_t
|
||||
{
|
||||
// the editor form
|
||||
TWidget *editor_widget = nullptr;
|
||||
|
||||
// contents of the text field for each item
|
||||
qstring txts[qnumber(names)] =
|
||||
{
|
||||
"Text one:\n This is text for item one",
|
||||
"Text two:\n And this is text for item two",
|
||||
"Text three:\n And finally text for the last item"
|
||||
};
|
||||
|
||||
// Current index for chooser list view
|
||||
size_t curidx = 0;
|
||||
// Form actions for control dialog
|
||||
form_actions_t *control_fa = nullptr;
|
||||
// Defines where to place new/existing editor window
|
||||
bool dock = false;
|
||||
|
||||
virtual bool idaapi run(size_t) override;
|
||||
|
||||
int editor_modcb(int fid, form_actions_t &fa);
|
||||
void open_editor_form(int options = 0);
|
||||
void close_editor_form();
|
||||
int control_modcb(int fid, form_actions_t &fa);
|
||||
void update_buttons(form_actions_t &fa);
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
struct of_chooser_t : public chooser_t
|
||||
{
|
||||
public:
|
||||
// this object must be allocated using `new`
|
||||
// as it used in the non-modal form
|
||||
of_chooser_t() : chooser_t()
|
||||
{
|
||||
columns = 1;
|
||||
static const int widths_[] = { 12 };
|
||||
static const char *const header_[] = { "Name" };
|
||||
widths = widths_;
|
||||
header = header_;
|
||||
}
|
||||
|
||||
virtual size_t idaapi get_count() const override { return qnumber(names); }
|
||||
virtual void idaapi get_row(
|
||||
qstrvec_t *cols,
|
||||
int *,
|
||||
chooser_item_attrs_t *,
|
||||
size_t n) const override
|
||||
{
|
||||
(*cols)[0] = names[n];
|
||||
}
|
||||
};
|
||||
|
||||
// Form actions for editor window
|
||||
enum editor_form_actions
|
||||
{
|
||||
TEXT_CHANGED = 1,
|
||||
ITEM_SELECTED = 2,
|
||||
};
|
||||
|
||||
// Form actions for control window
|
||||
enum control_form_actions
|
||||
{
|
||||
BTN_DOCK = 10,
|
||||
BTN_UNDOCK = 11,
|
||||
BTN_OPEN = 12,
|
||||
BTN_CLOSE = 13,
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
inline void enable_button(form_actions_t &fa, int fid, bool enabled)
|
||||
{
|
||||
fa.enable_field(fid, enabled);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Update control window buttons state
|
||||
void plugin_ctx_t::update_buttons(form_actions_t &fa)
|
||||
{
|
||||
bool visible = editor_widget != NULL;
|
||||
enable_button(fa, 10, !dock && visible);
|
||||
enable_button(fa, 11, dock && visible);
|
||||
enable_button(fa, 12, !visible);
|
||||
enable_button(fa, 13, visible);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// this callback is called when the user clicks on a button
|
||||
static int idaapi btn_cb(int, form_actions_t &)
|
||||
{
|
||||
msg("button has been pressed -> \n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// this callback is called when something happens in our non-modal editor form
|
||||
static int idaapi editor_modcb_(int fid, form_actions_t &fa)
|
||||
{
|
||||
plugin_ctx_t &ctx = *(plugin_ctx_t *)fa.get_ud();
|
||||
return ctx.editor_modcb(fid, fa);
|
||||
}
|
||||
int plugin_ctx_t::editor_modcb(int fid, form_actions_t &fa)
|
||||
{
|
||||
switch ( fid )
|
||||
{
|
||||
case CB_INIT: // Initialization
|
||||
msg("init editor form\n");
|
||||
break;
|
||||
case CB_CLOSE: // Closing the form
|
||||
msg("closing editor form\n");
|
||||
// mark the form as closed
|
||||
editor_widget = nullptr;
|
||||
// If control form exists then update buttons
|
||||
if ( control_fa != nullptr )
|
||||
update_buttons(*control_fa);
|
||||
break;
|
||||
case TEXT_CHANGED: // Text changed
|
||||
{
|
||||
textctrl_info_t ti;
|
||||
fa.get_text_value(1, &ti);
|
||||
txts[curidx] = ti.text;
|
||||
}
|
||||
msg("text has been changed\n");
|
||||
break;
|
||||
case ITEM_SELECTED: // list item selected
|
||||
{
|
||||
sizevec_t sel;
|
||||
if ( fa.get_chooser_value(2, &sel) )
|
||||
{
|
||||
curidx = sel[0];
|
||||
textctrl_info_t ti;
|
||||
ti.cb = sizeof(textctrl_info_t);
|
||||
ti.text = txts[curidx];
|
||||
fa.set_text_value(1, &ti);
|
||||
}
|
||||
}
|
||||
msg("selection has been changed\n");
|
||||
break;
|
||||
default:
|
||||
msg("unknown id %d\n", fid);
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
// create and open the editor form
|
||||
void plugin_ctx_t::open_editor_form(int options)
|
||||
{
|
||||
static const char formdef[] =
|
||||
"BUTTON NO NONE\n" // we do not want the standard buttons on the form
|
||||
"BUTTON YES NONE\n"
|
||||
"BUTTON CANCEL NONE\n"
|
||||
"Editor form\n" // the form title. it is also used to refer to the form later
|
||||
"\n"
|
||||
"%/%*" // placeholder for the 'editor_modcb' callback
|
||||
"\n"
|
||||
"<List:E2:30:30:1::><|><Text:t1:30:40:::>\n" // text edit control and chooser control separated by splitter
|
||||
"\n";
|
||||
// structure for text edit control
|
||||
textctrl_info_t ti;
|
||||
ti.cb = sizeof(textctrl_info_t);
|
||||
ti.text = txts[0];
|
||||
// structure for chooser list view
|
||||
of_chooser_t *ofch = new of_chooser_t();
|
||||
// selection for chooser list view
|
||||
sizevec_t selected;
|
||||
selected.push_back(0); // first item by default
|
||||
editor_widget = open_form(formdef,
|
||||
options,
|
||||
editor_modcb_, this,
|
||||
ofch, &selected,
|
||||
&ti);
|
||||
} //lint !e429 custodial pointer 'ofch' likely not freed nor returned
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void plugin_ctx_t::close_editor_form()
|
||||
{
|
||||
msg("closing editor widget\n");
|
||||
close_widget(editor_widget, WCLS_CLOSE_LATER);
|
||||
editor_widget = nullptr;
|
||||
}
|
||||
//--------------------------------------------------------------------------
|
||||
inline void dock_form(bool _dock)
|
||||
{
|
||||
set_dock_pos("Editor form",
|
||||
NULL,
|
||||
_dock ? DP_INSIDE : DP_FLOATING);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// this callback is called when something happens in our non-modal control form
|
||||
static int idaapi control_modcb_(int fid, form_actions_t &fa)
|
||||
{
|
||||
plugin_ctx_t &ctx = *(plugin_ctx_t *)fa.get_ud();
|
||||
return ctx.control_modcb(fid, fa);
|
||||
}
|
||||
int plugin_ctx_t::control_modcb(int fid, form_actions_t &fa)
|
||||
{
|
||||
switch ( fid )
|
||||
{
|
||||
case CB_INIT: // Initialization
|
||||
msg("init control form\n");
|
||||
dock = false;
|
||||
control_fa = &fa; // remember the 'fa' for the future
|
||||
update_buttons(fa);
|
||||
break;
|
||||
case CB_CLOSE: // Closing
|
||||
msg("closing control form\n");
|
||||
control_fa = NULL;
|
||||
return 1;
|
||||
case BTN_DOCK:
|
||||
msg("dock editor form\n");
|
||||
dock = true;
|
||||
dock_form(dock);
|
||||
break;
|
||||
case BTN_UNDOCK:
|
||||
msg("undock editor form\n");
|
||||
dock = false;
|
||||
dock_form(dock);
|
||||
break;
|
||||
case BTN_OPEN:
|
||||
msg("open editor form\n");
|
||||
open_editor_form(WOPN_DP_TAB|WOPN_RESTORE);
|
||||
dock_form(dock);
|
||||
break;
|
||||
case BTN_CLOSE:
|
||||
close_editor_form();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
update_buttons(fa);
|
||||
return 1;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// the main function of the plugin
|
||||
bool idaapi plugin_ctx_t::run(size_t)
|
||||
{
|
||||
// first open the editor form
|
||||
open_editor_form(WOPN_RESTORE);
|
||||
|
||||
static const char control_form[] =
|
||||
"BUTTON NO NONE\n" // do not display standard buttons at the bottom
|
||||
"BUTTON YES NONE\n"
|
||||
"BUTTON CANCEL NONE\n"
|
||||
"Control form\n" // the title. it is used to refer to the form later
|
||||
"%/%*" // placeholder for control_modcb
|
||||
"<Dock:B10:30:::><Undock:B11:30:::><Show:B12:30:::><Hide:B13:30:::>\n"; // Create control buttons
|
||||
|
||||
open_form(control_form,
|
||||
WOPN_RESTORE,
|
||||
control_modcb_, this,
|
||||
btn_cb, btn_cb, btn_cb, btn_cb);
|
||||
set_dock_pos("Control form", NULL, DP_FLOATING, 0, 0, 300, 100);
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// initialize the plugin
|
||||
static plugmod_t *idaapi init()
|
||||
{
|
||||
return new plugin_ctx_t;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
plugin_t PLUGIN =
|
||||
{
|
||||
IDP_INTERFACE_VERSION,
|
||||
PLUGIN_MULTI, // The plugin can work with multiple idbs in parallel
|
||||
init,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
"Open non-modal form sample",// the preferred short name of the plugin
|
||||
nullptr,
|
||||
};
|
||||
2546
idasdk76/plugins/pdb/common.cpp
Normal file
2546
idasdk76/plugins/pdb/common.cpp
Normal file
File diff suppressed because it is too large
Load Diff
3750
idasdk76/plugins/pdb/cvconst.h
Normal file
3750
idasdk76/plugins/pdb/cvconst.h
Normal file
File diff suppressed because it is too large
Load Diff
4458
idasdk76/plugins/pdb/dbghelp.h
Normal file
4458
idasdk76/plugins/pdb/dbghelp.h
Normal file
File diff suppressed because it is too large
Load Diff
7560
idasdk76/plugins/pdb/dia2.h
Normal file
7560
idasdk76/plugins/pdb/dia2.h
Normal file
File diff suppressed because it is too large
Load Diff
15
idasdk76/plugins/pdb/makefile
Normal file
15
idasdk76/plugins/pdb/makefile
Normal file
@@ -0,0 +1,15 @@
|
||||
PROC=pdb
|
||||
CONFIGS=pdb.cfg
|
||||
|
||||
ifdef __NT__
|
||||
O1=old
|
||||
STDLIBS += ole32.lib
|
||||
STDLIBS += oleaut32.lib
|
||||
else
|
||||
LIBS += $(L)network$(A)
|
||||
endif
|
||||
|
||||
include ../plugin.mak
|
||||
|
||||
$(F)pdb$(O): CC_WNO-$(call gte,$(GCC_VERSION),6.1) += -Wno-null-dereference
|
||||
|
||||
40
idasdk76/plugins/pdb/misc.cpp
Normal file
40
idasdk76/plugins/pdb/misc.cpp
Normal file
@@ -0,0 +1,40 @@
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
static const char *symtag_to_string(uint32 tag)
|
||||
{
|
||||
static const char *const names[] =
|
||||
{
|
||||
"Null",
|
||||
"Exe",
|
||||
"Compiland",
|
||||
"CompilandDetails",
|
||||
"CompilandEnv",
|
||||
"Function",
|
||||
"Block",
|
||||
"Data",
|
||||
"Annotation",
|
||||
"Label",
|
||||
"PublicSymbol",
|
||||
"UDT",
|
||||
"Enum",
|
||||
"FunctionType",
|
||||
"PointerType",
|
||||
"ArrayType",
|
||||
"BaseType",
|
||||
"Typedef",
|
||||
"BaseClass",
|
||||
"Friend",
|
||||
"FunctionArgType",
|
||||
"FuncDebugStart",
|
||||
"FuncDebugEnd",
|
||||
"UsingNamespace",
|
||||
"VTableShape",
|
||||
"VTable",
|
||||
"Custom",
|
||||
"Thunk",
|
||||
"CustomType",
|
||||
"ManagedType",
|
||||
"Dimension"
|
||||
};
|
||||
return tag < qnumber(names) ? names[tag] : "???";
|
||||
}
|
||||
1150
idasdk76/plugins/pdb/msdia.cpp
Normal file
1150
idasdk76/plugins/pdb/msdia.cpp
Normal file
File diff suppressed because it is too large
Load Diff
81
idasdk76/plugins/pdb/msdia.hpp
Normal file
81
idasdk76/plugins/pdb/msdia.hpp
Normal file
@@ -0,0 +1,81 @@
|
||||
|
||||
#ifndef MSDIA_HPP
|
||||
#define MSDIA_HPP
|
||||
|
||||
#include "pdbaccess.hpp"
|
||||
#include "pdblocal.hpp"
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
struct pdb_session_t
|
||||
{
|
||||
HMODULE dia_hmod;
|
||||
int refcount;
|
||||
local_pdb_access_t *pdb_access;
|
||||
|
||||
pdb_session_t()
|
||||
: dia_hmod(NULL),
|
||||
refcount(1),
|
||||
pdb_access(NULL),
|
||||
pSource(NULL)
|
||||
{
|
||||
session_count++;
|
||||
}
|
||||
~pdb_session_t();
|
||||
|
||||
HRESULT open_session(const pdbargs_t &pdbargs);
|
||||
void close();
|
||||
const char *get_used_fname() const { return used_fname.begin(); }
|
||||
|
||||
private:
|
||||
DECLARE_UNCOPYABLE(pdb_session_t)
|
||||
HRESULT create_dia_source(int *dia_version);
|
||||
|
||||
IDiaDataSource *pSource;
|
||||
qwstring winput;
|
||||
qwstring wspath;
|
||||
enum load_data_type_t
|
||||
{
|
||||
EXE_LOCAL,
|
||||
MEM_LOCAL, // PDB_PLUGIN
|
||||
EXE_WIN32, // PDB_WIN32_SERVER
|
||||
MEM_WIN32, // PDB_WIN32_SERVER
|
||||
};
|
||||
HRESULT load_data_for_exe(const pdbargs_t &pdbargs, load_data_type_t type);
|
||||
HRESULT load_input_path(const pdbargs_t &pdbargs, const char *input_path);
|
||||
|
||||
// The total number of different PDB sessions; kept track of
|
||||
// in order to know when we can safely CoUninitialize().
|
||||
static int session_count;
|
||||
|
||||
// Whether COM is initialized in this thread.
|
||||
static bool co_initialized;
|
||||
#ifdef _DEBUG
|
||||
public:
|
||||
qstring _pdb_path;
|
||||
#endif
|
||||
qstring used_fname;
|
||||
};
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
class pdb_session_ref_t
|
||||
{
|
||||
public:
|
||||
pdb_session_t *session; // refcounted object
|
||||
|
||||
pdb_session_ref_t(void) : session(NULL) {}
|
||||
pdb_session_ref_t(const pdb_session_ref_t &r);
|
||||
~pdb_session_ref_t();
|
||||
|
||||
pdb_session_ref_t &operator=(const pdb_session_ref_t &r);
|
||||
void create_session();
|
||||
void close();
|
||||
bool empty() const { return session == NULL; }
|
||||
bool opened() const { return !empty() && session->pdb_access != NULL; }
|
||||
HRESULT open_session(const pdbargs_t &args);
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
const char *pdberr(int code);
|
||||
|
||||
#endif
|
||||
202
idasdk76/plugins/pdb/old.cpp
Normal file
202
idasdk76/plugins/pdb/old.cpp
Normal file
@@ -0,0 +1,202 @@
|
||||
|
||||
// Old interface to PDB files
|
||||
// It is used as a fallback method if DIA interface fails
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#pragma pack(push, 8)
|
||||
#include "cvconst.h"
|
||||
#include "dbghelp.h"
|
||||
#pragma pack(pop)
|
||||
|
||||
#include <ida.hpp>
|
||||
#include <idp.hpp>
|
||||
#include <err.h>
|
||||
#include "oldpdb.h"
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
typedef DWORD IMAGEAPI SymSetOptions_t(IN DWORD SymOptions);
|
||||
typedef BOOL IMAGEAPI SymInitialize_t(IN HANDLE hProcess, IN LPCSTR UserSearchPath, IN BOOL fInvadeProcess);
|
||||
typedef DWORD64 IMAGEAPI SymLoadModule64_t(IN HANDLE hProcess, IN HANDLE hFile, IN PSTR ImageName, IN PSTR ModuleName, IN DWORD64 BaseOfDll, IN DWORD SizeOfDll);
|
||||
typedef BOOL IMAGEAPI SymEnumSymbols_t(IN HANDLE hProcess, IN ULONG64 BaseOfDll, IN PCSTR Mask, IN PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback, IN PVOID UserContext);
|
||||
typedef BOOL IMAGEAPI SymUnloadModule64_t(IN HANDLE hProcess, IN DWORD64 BaseOfDll);
|
||||
typedef BOOL IMAGEAPI SymCleanup_t(IN HANDLE hProcess);
|
||||
|
||||
static HINSTANCE dbghelp = NULL;
|
||||
static SymSetOptions_t *pSymSetOptions = NULL;
|
||||
static SymInitialize_t *pSymInitialize = NULL;
|
||||
static SymLoadModule64_t *pSymLoadModule64 = NULL;
|
||||
static SymEnumSymbols_t *pSymEnumSymbols = NULL;
|
||||
static SymUnloadModule64_t *pSymUnloadModule64 = NULL;
|
||||
static SymCleanup_t *pSymCleanup = NULL;
|
||||
static int symbols_found = 0;
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Dynamically load and link to DBGHELP or IMAGEHLP libraries
|
||||
// Return: success
|
||||
static bool setup_pointers(bool *must_free)
|
||||
{
|
||||
char dll[QMAXPATH];
|
||||
|
||||
// check if it's already loaded
|
||||
dbghelp = GetModuleHandle("dbghelp.dll");
|
||||
|
||||
*must_free = false;
|
||||
if ( dbghelp == NULL )
|
||||
{
|
||||
// nope, load it
|
||||
// use search_path to avoid dll current directory attacks
|
||||
if ( !search_path(dll, sizeof(dll), "dbghelp.dll", false) )
|
||||
return false;
|
||||
dbghelp = LoadLibrary(dll);
|
||||
*must_free = true;
|
||||
}
|
||||
|
||||
if ( dbghelp == NULL )
|
||||
{
|
||||
deb(IDA_DEBUG_DBGINFO, "PDB plugin: failed to load DBGHELP.DLL");
|
||||
}
|
||||
else
|
||||
{
|
||||
*(FARPROC*)&pSymSetOptions = GetProcAddress(dbghelp, "SymSetOptions");
|
||||
*(FARPROC*)&pSymInitialize = GetProcAddress(dbghelp, "SymInitialize");
|
||||
*(FARPROC*)&pSymLoadModule64 = GetProcAddress(dbghelp, "SymLoadModule64");
|
||||
*(FARPROC*)&pSymEnumSymbols = GetProcAddress(dbghelp, "SymEnumSymbols");
|
||||
*(FARPROC*)&pSymUnloadModule64 = GetProcAddress(dbghelp, "SymUnloadModule64");
|
||||
*(FARPROC*)&pSymCleanup = GetProcAddress(dbghelp, "SymCleanup");
|
||||
|
||||
if ( pSymSetOptions != NULL
|
||||
&& pSymInitialize != NULL
|
||||
&& pSymLoadModule64 != NULL
|
||||
&& pSymUnloadModule64 != NULL
|
||||
&& pSymCleanup != NULL
|
||||
&& pSymEnumSymbols != NULL ) // required XP or higher
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
deb(IDA_DEBUG_DBGINFO, "PDB plugin: Essential DBGHELP.DLL functions are missing\n");
|
||||
if ( dbghelp != NULL )
|
||||
{
|
||||
FreeLibrary(dbghelp);
|
||||
dbghelp = NULL;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// New method: symbol enumeration callback
|
||||
//lint -e{818} could be declared as pointing to const
|
||||
static BOOL CALLBACK EnumerateSymbolsProc(
|
||||
PSYMBOL_INFO psym,
|
||||
ULONG /*SymbolSize*/,
|
||||
PVOID delta)
|
||||
{
|
||||
symbols_found++;
|
||||
ea_t ea = (ea_t)(psym->Address + *(adiff_t*)delta);
|
||||
const char *name = psym->Name;
|
||||
|
||||
int maybe_func = 0; // maybe
|
||||
switch ( psym->Tag )
|
||||
{
|
||||
case SymTagFunction:
|
||||
case SymTagThunk:
|
||||
maybe_func = 1;
|
||||
break;
|
||||
case SymTagNull:
|
||||
case SymTagExe:
|
||||
case SymTagCompiland:
|
||||
case SymTagCompilandDetails:
|
||||
case SymTagCompilandEnv:
|
||||
case SymTagData:
|
||||
case SymTagAnnotation:
|
||||
case SymTagUDT:
|
||||
case SymTagEnum:
|
||||
case SymTagFunctionType:
|
||||
case SymTagPointerType:
|
||||
case SymTagArrayType:
|
||||
case SymTagBaseType:
|
||||
case SymTagTypedef:
|
||||
case SymTagBaseClass:
|
||||
case SymTagFunctionArgType:
|
||||
case SymTagUsingNamespace:
|
||||
case SymTagVTableShape:
|
||||
case SymTagVTable:
|
||||
case SymTagCustom:
|
||||
case SymTagCustomType:
|
||||
case SymTagManagedType:
|
||||
case SymTagDimension:
|
||||
maybe_func = -1;
|
||||
break;
|
||||
case SymTagBlock:
|
||||
case SymTagLabel:
|
||||
case SymTagFuncDebugStart:
|
||||
case SymTagFuncDebugEnd:
|
||||
maybe_func = 2;
|
||||
break;
|
||||
case SymTagPublicSymbol:
|
||||
case SymTagFriend:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
bool ok = apply_name(ea, name, maybe_func);
|
||||
// New dbghelp.dll/symsrv.dll files return names without the terminating zero.
|
||||
// So, as soon as we have a long name, shorter names will have garbage at the end.
|
||||
// Clean up the name to avoid problems.
|
||||
size_t len = strlen(name);
|
||||
memset((void*)name, '\0', len);
|
||||
return ok;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Display a system error message
|
||||
static void error_msg(const char *name)
|
||||
{
|
||||
int code = GetLastError();
|
||||
if ( code != 0 )
|
||||
msg("%s: %s\n", name, winerr(code));
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Try old method of loading symbols
|
||||
bool old_pdb_plugin(ea_t loaded_base, const char *input, const char *spath)
|
||||
{
|
||||
bool ok = false;
|
||||
bool must_free;
|
||||
if ( setup_pointers(&must_free) )
|
||||
{
|
||||
pSymSetOptions(SYMOPT_LOAD_LINES|SYMOPT_FAVOR_COMPRESSED|SYMOPT_NO_PROMPTS);
|
||||
|
||||
void *fake_proc = (void *)(uintptr_t)0xBEEFFEED;
|
||||
if ( !pSymInitialize(fake_proc, spath, FALSE) )
|
||||
{
|
||||
error_msg("SymInitialize");
|
||||
}
|
||||
else
|
||||
{
|
||||
DWORD64 symbase = pSymLoadModule64(fake_proc, 0, (char*)input, NULL, loaded_base, 0);
|
||||
if ( symbase != 0 )
|
||||
{
|
||||
load_vc_til();
|
||||
|
||||
symbols_found = 0;
|
||||
adiff_t delta = adiff_t(loaded_base - symbase);
|
||||
ok = pSymEnumSymbols(fake_proc, symbase, NULL, EnumerateSymbolsProc, &delta)
|
||||
&& symbols_found > 0;
|
||||
if ( !ok )
|
||||
error_msg("EnumSymbols");
|
||||
if ( !pSymUnloadModule64(fake_proc, symbase) )
|
||||
error_msg("SymUnloadModule64");
|
||||
}
|
||||
if ( !pSymCleanup(fake_proc) )
|
||||
error_msg("SymCleanup");
|
||||
}
|
||||
if ( must_free )
|
||||
{
|
||||
FreeLibrary(dbghelp);
|
||||
dbghelp = NULL;
|
||||
}
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
9
idasdk76/plugins/pdb/oldpdb.h
Normal file
9
idasdk76/plugins/pdb/oldpdb.h
Normal file
@@ -0,0 +1,9 @@
|
||||
|
||||
// Common definitions for the old and new pdb plugins
|
||||
|
||||
// helper functions provided by the new pdb plugin
|
||||
bool apply_name(ea_t ea, const qstring &name, int maybe_func);
|
||||
void load_vc_til(void);
|
||||
|
||||
// entry point of the old pdb plugin
|
||||
bool old_pdb_plugin(ea_t loaded_base, const char *input, const char *spath);
|
||||
47
idasdk76/plugins/pdb/pdb.cfg
Normal file
47
idasdk76/plugins/pdb/pdb.cfg
Normal file
@@ -0,0 +1,47 @@
|
||||
// PDB plugin
|
||||
|
||||
// PDB information provider
|
||||
#define PDB_PROVIDER_MSDIA 1 // use MSDIA local/remote provider
|
||||
#define PDB_PROVIDER_PDBIDA 2 // use PDBIDA provider
|
||||
//PDB_PROVIDER = PDB_PROVIDER_PDBIDA
|
||||
|
||||
// it is possible to specify the desired provider in the command line:
|
||||
// ida -Opdb:off input_file
|
||||
// ida -Opdb:msdia input_file
|
||||
// ida -Opdb:pdbida input_file
|
||||
|
||||
// Symbol search path
|
||||
// The _NT_SYMBOL_PATH environment variable overrides this setting.
|
||||
// If none of these variables is set then the default value will be used:
|
||||
// "SRV*CACHEDIR*http://msdl.microsoft.com/download/symbols"
|
||||
// where
|
||||
// CACHEDIR=%TEMP%\ida for Windows
|
||||
// CACHEDIR=$TMPDIR/ida or $TMP/ida or /tmp/ida for non-Windows OSes
|
||||
//
|
||||
//_NT_SYMBOL_PATH = "SRV*c:\\symbols*http://symbols.mozilla.org/firefox;SRV*c:\\symbols*http://msdl.microsoft.com/download/symbols";
|
||||
|
||||
// Network communications while looking for PDB file can be restricted.
|
||||
// Valid only for PDBIDA provider.
|
||||
#define PDB_NETWORK_OFF 0 // local directories search only
|
||||
#define PDB_NETWORK_PE 1 // local directories search for COFF, full search for PE
|
||||
#define PDB_NETWORK_ON 2 // no restrictions
|
||||
//PDB_NETWORK = PDB_NETWORK_PE
|
||||
|
||||
// PDBIDA is able to load MSF 7.0 PDB files only.
|
||||
// MSDIA can load all PDB files, including old MSF 2.0 files.
|
||||
// If you set the following option to YES, IDA will automatically switch
|
||||
// to MSDIA for old files.
|
||||
// Please note that under Linux/macOS the MSDIA provider requires you to configure
|
||||
// the win32_remote.exe server because it can run only on Windows.
|
||||
// It is possible to specify the desired behavior in the command line:
|
||||
// ida -Opdb:fallback input_file
|
||||
// ida -Opdb:nofallback input_file
|
||||
PDB_MSDIA_FALLBACK = NO
|
||||
|
||||
// remote server where win32_remote.exe is running
|
||||
// used when loading PDB symbols on non-Windows platforms
|
||||
// NB: it will be used only if there is not already an existing debugging session started
|
||||
PDB_REMOTE_SERVER = "localhost";
|
||||
PDB_REMOTE_PORT = 23946
|
||||
// password for the remote server
|
||||
PDB_REMOTE_PASSWD = "";
|
||||
1414
idasdk76/plugins/pdb/pdb.cpp
Normal file
1414
idasdk76/plugins/pdb/pdb.cpp
Normal file
File diff suppressed because it is too large
Load Diff
217
idasdk76/plugins/pdb/pdb.hpp
Normal file
217
idasdk76/plugins/pdb/pdb.hpp
Normal file
@@ -0,0 +1,217 @@
|
||||
//
|
||||
// Copyright (c) 2005-2021 Hex-Rays SA <support@hex-rays.com>
|
||||
// ALL RIGHTS RESERVED.
|
||||
//
|
||||
#pragma once
|
||||
#include <idp.hpp>
|
||||
#include <idd.hpp>
|
||||
#include <typeinf.hpp>
|
||||
#include "../../ldr/pe/pe.h"
|
||||
|
||||
#define PDB_NODE_NAME "$ pdb"
|
||||
#define PDB_DLLBASE_NODE_IDX 0
|
||||
#define PDB_DLLNAME_NODE_IDX 0
|
||||
#define PDB_LOADING_WIN32_DBG 1
|
||||
#define PDB_TYPESONLY_NODE_IDX 2
|
||||
|
||||
enum pdb_callcode_t
|
||||
{
|
||||
// user invoked 'load pdb' command, load pdb for the input file.
|
||||
// after invocation, result (boolean) is stored in: netnode(PDB_NODE_NAME).altval(PDB_DLLBASE_NODE_IDX)
|
||||
PDB_CC_USER = 0,
|
||||
// ida decided to call the plugin itself
|
||||
PDB_CC_IDA = 1,
|
||||
// load additional pdb. This is semantically the same as
|
||||
// PDB_CC_USER (i.e., "File > Load file > PDB file..."), except
|
||||
// it won't ask the user for the data; rather it expects it in
|
||||
// netnode(PDB_NODE_NAME):
|
||||
// load_addr: netnode(PDB_NODE_NAME).altval(PDB_DLLBASE_NODE_IDX)
|
||||
// dll_name: netnode(PDB_NODE_NAME).supstr(PDB_DLLNAME_NODE_IDX)
|
||||
PDB_CC_USER_WITH_DATA = 3,
|
||||
// load debug info from the COFF file
|
||||
// ida decided to call the plugin itself
|
||||
// dbginfo_params_t: netnode(DBGINFO_PARAM_NODE_NAME).supval(DBGINFO_PARAMS_KEY)
|
||||
PDB_CC_IDA_COFF = 4,
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
struct pdb_signature_t
|
||||
{
|
||||
uint32 guid[4]; // if all zeroes, then consider as non-existing
|
||||
uint32 sig;
|
||||
uint32 age;
|
||||
pdb_signature_t(void) { memset(this, 0, sizeof(*this)); }
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
struct pdbargs_t
|
||||
{
|
||||
qstring pdb_path; // Path to PDB file.
|
||||
qstring input_path; // Path to PE file with associated PDB.
|
||||
pdb_signature_t pdb_sign;
|
||||
qstring spath;
|
||||
ea_t loaded_base;
|
||||
void *user_data;
|
||||
uint32 flags;
|
||||
#define PDBFLG_DBG_MODULE 0x0001
|
||||
#define PDBFLG_ONLY_TYPES 0x0002
|
||||
#define PDBFLG_EFD 0x0004
|
||||
#define PDBFLG_COFF_FILE 0x0008
|
||||
#define PDBFLG_USE_HTTP 0x0100
|
||||
|
||||
pdbargs_t(void)
|
||||
: loaded_base(BADADDR),
|
||||
user_data(NULL),
|
||||
flags(0)
|
||||
{}
|
||||
|
||||
// If true, we are in a debugging session and the file specified by
|
||||
// input_path is an additional module that has been loaded by the
|
||||
// debugger itself.
|
||||
bool is_dbg_module(void) const
|
||||
{
|
||||
return (flags & PDBFLG_DBG_MODULE) != 0;
|
||||
}
|
||||
// PDB?
|
||||
bool is_pdbfile(void) const { return (flags & PDBFLG_COFF_FILE) == 0; }
|
||||
bool use_http() const { return (flags & PDBFLG_USE_HTTP) != 0; }
|
||||
|
||||
const char *fname(void) const
|
||||
{
|
||||
return !pdb_path.empty() ? pdb_path.begin() : input_path.c_str();
|
||||
}
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
struct pdb_ctx_t : public plugmod_t, public event_listener_t
|
||||
{
|
||||
processor_t &ph;
|
||||
|
||||
// PDB search path (in _NT_SYMBOL_PATH format)
|
||||
qstring full_sympath;
|
||||
|
||||
peheader_t pe;
|
||||
|
||||
// config options
|
||||
int pdb_remote_port = DEBUGGER_PORT_NUMBER;
|
||||
int pdb_remote_port_64 = -1;
|
||||
qstring pdb_remote_server;
|
||||
qstring pdb_remote_passwd;
|
||||
#define PDB_PROVIDER_MSDIA 1
|
||||
uint pdb_provider = PDB_PROVIDER_MSDIA;
|
||||
#define PDB_NETWORK_OFF 0 // local directories search only
|
||||
#define PDB_NETWORK_PE 1 // local directories search for COFF, full search for PE
|
||||
#define PDB_NETWORK_ON 2 // no restrictions
|
||||
uint pdb_network = PDB_NETWORK_PE;
|
||||
bool use_http(bool is_pe) const
|
||||
{
|
||||
bool ok = pdb_network == PDB_NETWORK_PE && is_pe
|
||||
|| pdb_network == PDB_NETWORK_ON;
|
||||
deb(IDA_DEBUG_DBGINFO, ok ? "PDB: symbol servers will be used\n"
|
||||
: "PDB: local directories search only\n");
|
||||
return ok;
|
||||
}
|
||||
|
||||
// Plugin options
|
||||
uint opt_provider = 0;
|
||||
// -1 don't specified
|
||||
// 0 set PDB_FALLBACK to false
|
||||
// 1 set PDB_FALLBACK to true
|
||||
int opt_fallback = -1;
|
||||
|
||||
using namelist_t = std::map<ea_t, qstring>;
|
||||
namelist_t namelist;
|
||||
|
||||
// srcinfo provider
|
||||
class pdb_provider_t *pdb_srcinfo_provider = nullptr;
|
||||
|
||||
pdb_ctx_t();
|
||||
virtual ~pdb_ctx_t();
|
||||
virtual bool idaapi run(size_t arg) override;
|
||||
virtual ssize_t idaapi on_event(ssize_t code, va_list va) override;
|
||||
|
||||
void parse_options(bool *opt_skip);
|
||||
|
||||
void init_sympaths();
|
||||
void load_vc_til(void) const;
|
||||
|
||||
// maybe_func: -1:no, 0-maybe, 1-yes, 2:no,but iscode
|
||||
bool apply_name_in_idb(ea_t ea, const qstring &name, int maybe_func, uint32 the_machine_type);
|
||||
bool apply_debug_info(pdbargs_t &pdbargs);
|
||||
|
||||
// printable register name
|
||||
bool get_pdb_register_info(int *p_reg, uint64 *p_mask, int machine, int reg);
|
||||
|
||||
// Because we need to be able to call the 'old' pdb plugin
|
||||
// code, which knows nothing about the til_builder_t (and
|
||||
// thus its 'machine_type' field, and also because, at the
|
||||
// very time we call the old pdb code, our til_builder_t
|
||||
// instance will have been long forgotten and destroyed,
|
||||
// we must keep this machine type information somewhere.
|
||||
uint32 g_machine_type = 0; // will be set to CV_CFL_80386 in ctor
|
||||
|
||||
private:
|
||||
//-------------------------------------------------------------------------
|
||||
int utf16_encidx = -1;
|
||||
int get_utf16_encoding_idx();
|
||||
|
||||
bool checked_types = false;
|
||||
bool has_sid = false;
|
||||
bool check_for_ids(ea_t ea, const char *name, bool has_typeinfo);
|
||||
|
||||
void alloc_pdb_srcinfo_provider();
|
||||
void free_pdb_srcinfo_provider();
|
||||
|
||||
public:
|
||||
//-------------------------------------------------------------------------
|
||||
//#define CHECK_CREATED_TYPES
|
||||
#ifdef CHECK_CREATED_TYPES
|
||||
struct type_to_check_t
|
||||
{
|
||||
// one of the following 3 will be valid:
|
||||
ea_t ea;
|
||||
int id;
|
||||
qstring name;
|
||||
|
||||
// the type itself
|
||||
tinfo_t type;
|
||||
};
|
||||
|
||||
qvector<type_to_check_t> types_to_check;
|
||||
int check_n = 0;
|
||||
|
||||
void check_tinfo(ea_t ea, int id, const char *name, const tinfo_t &tif)
|
||||
{
|
||||
type_to_check_t &tc = types_to_check.push_back();
|
||||
tc.ea = ea;
|
||||
tc.id = id;
|
||||
tc.name = name;
|
||||
tc.type = tif;
|
||||
}
|
||||
|
||||
void check_added_types(void)
|
||||
{
|
||||
for ( const auto &tc : types_to_check )
|
||||
{
|
||||
if ( !tc.type.is_correct() )
|
||||
{
|
||||
msg("%d: INCORRECT TYPE ", check_n);
|
||||
if ( !tc.name.empty() )
|
||||
msg("%s", tc.name.begin());
|
||||
else if ( tc.ea != BADADDR )
|
||||
msg("%a", tc.ea);
|
||||
else
|
||||
msg("#%d", tc.id);
|
||||
qstring res;
|
||||
tc.type.print(&res);
|
||||
msg(": %s\n", res.c_str());
|
||||
check_n++;
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
inline void check_tinfo(ea_t,int,const char*,const tinfo_t &) {}
|
||||
inline void check_added_types(void) {}
|
||||
#endif
|
||||
};
|
||||
extern int data_id;
|
||||
661
idasdk76/plugins/pdb/pdbaccess.hpp
Normal file
661
idasdk76/plugins/pdb/pdbaccess.hpp
Normal file
@@ -0,0 +1,661 @@
|
||||
|
||||
|
||||
#ifndef PDBACCESS__H
|
||||
#define PDBACCESS__H
|
||||
|
||||
#include <pro.h>
|
||||
#include "cvconst.h"
|
||||
|
||||
#ifdef __NT__
|
||||
#include <windows.h>
|
||||
#include <oaidl.h>
|
||||
#include "dia2.h"
|
||||
#else
|
||||
// FIXME: It'd be good if those windows declarations for non-windows
|
||||
// systems were somewhere else than in the PE loader.
|
||||
#include "../../ldr/pe/mycor.h"
|
||||
#endif
|
||||
#include "pdb.hpp"
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
class pdb_access_t;
|
||||
class local_pdb_access_t;
|
||||
class remote_pdb_access_t;
|
||||
|
||||
struct pdb_exception_t
|
||||
{
|
||||
pdb_exception_t(const qstring &_what) : what(_what) {}
|
||||
qstring what;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
#ifdef __NT__
|
||||
enum sym_token_t : uint64
|
||||
#else
|
||||
enum sym_token_t
|
||||
#endif
|
||||
{
|
||||
t_start = 1 << 0,
|
||||
// bool
|
||||
t_bool_start = t_start,
|
||||
t_constType = t_bool_start,
|
||||
t_isStatic = 1 << 1,
|
||||
t_virtual = 1 << 2,
|
||||
t_volatileType = 1 << 3,
|
||||
t_code = 1 << 4,
|
||||
t_hasAssignmentOperator = 1 << 5,
|
||||
t_hasCastOperator = 1 << 6,
|
||||
t_function = 1 << 7, // FIXME!
|
||||
t_constructor = 1 << 8,
|
||||
t_isVirtualBaseClass = 1 << 9,
|
||||
t_bool_end = t_isVirtualBaseClass,
|
||||
|
||||
// dword
|
||||
t_dword_start = 1 << 10,
|
||||
t_backEndMajor = t_dword_start,
|
||||
t_baseType = 1 << 11,
|
||||
t_bitPosition = 1 << 12,
|
||||
t_callingConvention = 1 << 13,
|
||||
t_count = 1 << 14,
|
||||
t_dataKind = 1 << 15,
|
||||
t_locationType = 1 << 16,
|
||||
t_registerId = 1 << 17,
|
||||
t_relativeVirtualAddress = 1 << 18,
|
||||
t_symIndexId = 1 << 19,
|
||||
t_symTag = 1 << 20,
|
||||
t_udtKind = 1 << 21,
|
||||
t_virtualBaseOffset = 1 << 22,
|
||||
t_machineType = 1 << 23,
|
||||
t_classParentId = 1 << 24,
|
||||
t_typeId = 1 << 25,
|
||||
t_lexicalParentId = 1 << 26,
|
||||
t_dword_end = t_lexicalParentId,
|
||||
|
||||
// dword64
|
||||
t_dword64_start = 1 << 27,
|
||||
t_length = t_dword64_start,
|
||||
t_dword64_end = t_length,
|
||||
|
||||
// string
|
||||
t_string_start = 1 << 28,
|
||||
t_name = t_string_start,
|
||||
t_string_end = t_name,
|
||||
|
||||
// long
|
||||
t_long_start = 1 << 29,
|
||||
t_offset = t_long_start,
|
||||
t_long_end = t_offset,
|
||||
|
||||
// ulonglong
|
||||
t_ulonglong_start = 1 << 30,
|
||||
t_virtualAddress = t_ulonglong_start,
|
||||
t_ulonglong_end = t_virtualAddress,
|
||||
|
||||
// variant
|
||||
t_variant_start = 1ULL << 31,
|
||||
t_value = t_variant_start,
|
||||
t_variant_end = t_value,
|
||||
|
||||
t_end = 1ULL << 32,
|
||||
};
|
||||
CASSERT(sizeof(sym_token_t) == 8);
|
||||
|
||||
inline bool is_sym_token_bool(sym_token_t t) { return t >= t_bool_start && t <= t_bool_end; }
|
||||
inline bool is_sym_token_dword(sym_token_t t) { return t >= t_dword_start && t <= t_dword_end; }
|
||||
inline bool is_sym_token_dword64(sym_token_t t) { return t >= t_dword64_start && t <= t_dword64_end; }
|
||||
// inline bool is_sym_token_pdb_sym(sym_token_t t) { return t >= t_pdb_sym_start && t <= t_pdb_sym_end; }
|
||||
inline bool is_sym_token_string(sym_token_t t) { return t >= t_string_start && t <= t_string_end; }
|
||||
inline bool is_sym_token_long(sym_token_t t) { return t >= t_long_start && t <= t_long_end; }
|
||||
inline bool is_sym_token_ulonglong(sym_token_t t) { return t >= t_ulonglong_start && t <= t_ulonglong_end; }
|
||||
inline bool is_sym_token_variant(sym_token_t t) { return t >= t_variant_start && t <= t_variant_end; } //-V560 is always true
|
||||
|
||||
|
||||
typedef uint64 token_mask_t;
|
||||
#define TOKEN_MASK_FULL token_mask_t(-1)
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// engine PDB symbol implementation identity
|
||||
enum pdb_sym_id_t
|
||||
{
|
||||
DIA_PDB_SYM,
|
||||
REMOTE_PDB_SYM,
|
||||
OWN_PDB_SYM,
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
struct pdb_sym_t
|
||||
{
|
||||
virtual HRESULT get_backEndMajor(DWORD *out) = 0;
|
||||
virtual HRESULT get_baseType(DWORD *out) = 0;
|
||||
virtual HRESULT get_bitPosition(DWORD *out) = 0;
|
||||
virtual HRESULT get_callingConvention(DWORD *out) = 0;
|
||||
virtual HRESULT get_code(BOOL *out) = 0;
|
||||
virtual HRESULT get_constructor(BOOL *out) = 0;
|
||||
virtual HRESULT get_isVirtualBaseClass(BOOL *out) = 0;
|
||||
virtual HRESULT get_constType(BOOL *out) = 0;
|
||||
virtual HRESULT get_count(DWORD *out) = 0;
|
||||
virtual HRESULT get_dataKind(DWORD *out) = 0;
|
||||
virtual HRESULT get_function(BOOL *out) = 0;
|
||||
virtual HRESULT get_hasAssignmentOperator(BOOL *out) = 0;
|
||||
virtual HRESULT get_hasCastOperator(BOOL *out) = 0;
|
||||
virtual HRESULT get_isStatic(BOOL *out) = 0;
|
||||
virtual HRESULT get_length(DWORD64 *out) = 0;
|
||||
virtual HRESULT get_lexicalParent(pdb_sym_t *out) = 0;
|
||||
virtual HRESULT get_locationType(DWORD *out) = 0;
|
||||
virtual HRESULT get_machineType(DWORD *out) = 0;
|
||||
virtual HRESULT get_name(qstring *out) = 0;
|
||||
virtual HRESULT get_offset(LONG *out) = 0;
|
||||
virtual HRESULT get_registerId(DWORD *out) = 0;
|
||||
virtual HRESULT get_relativeVirtualAddress(DWORD *out) = 0;
|
||||
virtual HRESULT get_symIndexId(DWORD *out) = 0;
|
||||
virtual HRESULT get_symTag(DWORD *out) = 0;
|
||||
virtual HRESULT get_udtKind(DWORD *out) = 0;
|
||||
virtual HRESULT get_value(VARIANT *out) = 0;
|
||||
virtual HRESULT get_virtual(BOOL *out) = 0;
|
||||
virtual HRESULT get_virtualAddress(ULONGLONG *out) = 0;
|
||||
virtual HRESULT get_virtualBaseOffset(DWORD *out) = 0;
|
||||
virtual HRESULT get_volatileType(BOOL *out) = 0;
|
||||
// Be very, very careful to _not_ use classParent if you can avoid it:
|
||||
// In case the symbol was *not* resolved through get_type(), the link
|
||||
// to the parent might be lost, and a bug in the DIA SDK will
|
||||
// return S_FALSE.
|
||||
virtual HRESULT get_classParent(pdb_sym_t *out) = 0;
|
||||
virtual HRESULT get_type(pdb_sym_t *out) = 0;
|
||||
//------------------------------------------------------------
|
||||
virtual HRESULT get_ordinal(DWORD *pRetVal) = 0;
|
||||
|
||||
// careful with this!
|
||||
virtual void steal_data(pdb_sym_t &other) = 0;
|
||||
|
||||
virtual pdb_sym_id_t whoami(void) = 0;
|
||||
virtual bool empty(void) = 0;
|
||||
|
||||
virtual ~pdb_sym_t() {}
|
||||
|
||||
// Declare, but ***don't*** define: we don't want
|
||||
// that to happen, and thus we'll have a linker
|
||||
// error if that would happen in the code.
|
||||
DECLARE_UNCOPYABLE(pdb_sym_t);
|
||||
|
||||
protected:
|
||||
pdb_sym_t() {}
|
||||
};
|
||||
DECLARE_TYPE_AS_MOVABLE(pdb_sym_t);
|
||||
|
||||
typedef janitor_t<pdb_sym_t*> pdb_sym_janitor_t;
|
||||
template <> inline pdb_sym_janitor_t::~janitor_t()
|
||||
{
|
||||
delete resource;
|
||||
resource = NULL;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
enum packing_info_t
|
||||
{
|
||||
SYMDAT_PACKED = 1,
|
||||
SYMDAT_UNPACKED
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
struct sym_data_t
|
||||
{
|
||||
sym_data_t(token_mask_t _tokens, const uchar *buf, size_t bufsize, packing_info_t _packing, bool *_warned);
|
||||
~sym_data_t();
|
||||
|
||||
DWORD get_id() const
|
||||
{
|
||||
DWORD id;
|
||||
if ( get_dword(t_symIndexId, &id) != S_OK )
|
||||
INTERR(30211);
|
||||
return id;
|
||||
}
|
||||
HRESULT get_bool(sym_token_t token, BOOL *out) const;
|
||||
HRESULT get_dword(sym_token_t token, DWORD *out) const;
|
||||
HRESULT get_dword64(sym_token_t token, DWORD64 *out) const;
|
||||
HRESULT get_pdb_sym(sym_token_t token, pdb_sym_t *out) const;
|
||||
HRESULT get_string(sym_token_t token, qstring *out) const;
|
||||
HRESULT get_dword(sym_token_t token, LONG *out) const;
|
||||
HRESULT get_ulonglong(sym_token_t token, ULONGLONG *out) const;
|
||||
HRESULT get_variant(sym_token_t token, VARIANT *out) const;
|
||||
|
||||
private:
|
||||
sym_data_t();
|
||||
|
||||
bool token_present(sym_token_t token) const
|
||||
{
|
||||
return (present & token) == token;
|
||||
}
|
||||
|
||||
void assert_token(sym_token_t token) const
|
||||
{
|
||||
if ( !token_present(token) )
|
||||
INTERR(30210);
|
||||
}
|
||||
|
||||
const BOOL *bool_ptr(sym_token_t token) const
|
||||
{
|
||||
return (const BOOL *)any_ptr(token, t_bool_start, t_bool_end);
|
||||
}
|
||||
|
||||
const DWORD *dword_ptr(sym_token_t token) const
|
||||
{
|
||||
return (const DWORD *)any_ptr(token, t_dword_start, t_dword_end);
|
||||
}
|
||||
|
||||
const DWORD64 *dword64_ptr(sym_token_t token) const
|
||||
{
|
||||
return (const DWORD64 *)any_ptr(token, t_dword64_start, t_dword64_end);
|
||||
}
|
||||
|
||||
const LONG *long_ptr(sym_token_t token) const
|
||||
{
|
||||
return (const LONG *)any_ptr(token, t_long_start, t_long_end);
|
||||
}
|
||||
|
||||
const ULONGLONG *uint64_ptr(sym_token_t token) const
|
||||
{
|
||||
return (const ULONGLONG *)any_ptr(token, t_ulonglong_start, t_ulonglong_end);
|
||||
}
|
||||
|
||||
const char **string_ptr(sym_token_t token) const
|
||||
{
|
||||
return (const char **)any_ptr(token, t_string_start, t_string_end);
|
||||
}
|
||||
|
||||
const VARIANT *variant_ptr(sym_token_t token) const
|
||||
{
|
||||
return (const VARIANT *)any_ptr(token, t_variant_start, t_variant_end);
|
||||
}
|
||||
|
||||
enum type_t
|
||||
{
|
||||
t_bool = 0,
|
||||
t_dword,
|
||||
t_dword64,
|
||||
t_string,
|
||||
t_long,
|
||||
t_ulonglong,
|
||||
t_variant,
|
||||
t_max
|
||||
};
|
||||
|
||||
static const uint32 sizes[];
|
||||
|
||||
const void *any_ptr(sym_token_t token, sym_token_t start, sym_token_t end) const;
|
||||
|
||||
token_mask_t present; // The tokens that are present in this instance.
|
||||
bytevec_t data;
|
||||
uint8 counters[t_max];
|
||||
|
||||
struct children_t
|
||||
{
|
||||
DWORD *ids;
|
||||
uint32 cnt;
|
||||
};
|
||||
children_t children_infos[SymTagMax];
|
||||
friend class remote_pdb_access_t; // accesses children_infos directly
|
||||
bool *warned;
|
||||
};
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
#ifdef __NT__
|
||||
struct dia_pdb_sym_t : public pdb_sym_t
|
||||
{
|
||||
dia_pdb_sym_t(pdb_access_t *_pdb_access, IDiaSymbol *_data, bool _own_sym)
|
||||
: pdb_access(_pdb_access),
|
||||
data(_data),
|
||||
own_sym(_own_sym)
|
||||
{}
|
||||
|
||||
~dia_pdb_sym_t()
|
||||
{
|
||||
if ( data != NULL && own_sym )
|
||||
{
|
||||
data->Release();
|
||||
data = NULL;
|
||||
}
|
||||
pdb_access = NULL;
|
||||
}
|
||||
|
||||
pdb_access_t *pdb_access;
|
||||
IDiaSymbol *data;
|
||||
bool own_sym;
|
||||
|
||||
pdb_sym_id_t whoami(void) { return DIA_PDB_SYM; }
|
||||
void set_symbol_data(IDiaSymbol *s, bool own)
|
||||
{
|
||||
data = s;
|
||||
own_sym = own;
|
||||
}
|
||||
bool empty(void) { return data == NULL; }
|
||||
|
||||
HRESULT get_backEndMajor(DWORD *out) { return data->get_backEndMajor(out); }
|
||||
HRESULT get_baseType(DWORD *out) { return data->get_baseType(out); }
|
||||
HRESULT get_bitPosition(DWORD *out) { return data->get_bitPosition(out); }
|
||||
HRESULT get_callingConvention(DWORD *out) { return data->get_callingConvention(out); }
|
||||
HRESULT get_code(BOOL *out) { return data->get_code(out); }
|
||||
HRESULT get_constType(BOOL *out) { return data->get_constType(out); }
|
||||
HRESULT get_count(DWORD *out) { return data->get_count(out); }
|
||||
HRESULT get_constructor(BOOL *out) { return data->get_constructor(out); }
|
||||
HRESULT get_isVirtualBaseClass(BOOL *out) { return data->get_virtualBaseClass(out); }
|
||||
HRESULT get_dataKind(DWORD *out) { return data->get_dataKind(out); }
|
||||
HRESULT get_function(BOOL *out) { return data->get_function(out); }
|
||||
HRESULT get_hasAssignmentOperator(BOOL *out) { return data->get_hasAssignmentOperator(out); }
|
||||
HRESULT get_hasCastOperator(BOOL *out) { return data->get_hasCastOperator(out); }
|
||||
HRESULT get_isStatic(BOOL *out) { return data->get_isStatic(out); }
|
||||
HRESULT get_length(DWORD64 *out) { return data->get_length(out); }
|
||||
HRESULT get_lexicalParent(pdb_sym_t *out)
|
||||
{
|
||||
IDiaSymbol *t;
|
||||
HRESULT res = data->get_lexicalParent(&t);
|
||||
return handle_related_symbol(res, t, out);
|
||||
}
|
||||
HRESULT get_locationType(DWORD *out) { return data->get_locationType(out); }
|
||||
HRESULT get_machineType(DWORD *out) { return data->get_machineType(out); }
|
||||
HRESULT get_name(qstring *out)
|
||||
{
|
||||
BSTR name;
|
||||
HRESULT hr = data->get_name(&name);
|
||||
return maybe_convert_bstr(out, hr, &name);
|
||||
}
|
||||
HRESULT get_offset(LONG *out) { return data->get_offset(out); }
|
||||
HRESULT get_registerId(DWORD *out) { return data->get_registerId(out); }
|
||||
HRESULT get_relativeVirtualAddress(DWORD *out) { return data->get_relativeVirtualAddress(out); }
|
||||
HRESULT get_symIndexId(DWORD *out) { return data->get_symIndexId(out); }
|
||||
HRESULT get_symTag(DWORD *out) { return data->get_symTag(out); }
|
||||
HRESULT get_udtKind(DWORD *out) { return data->get_udtKind(out); }
|
||||
HRESULT get_value(VARIANT *out) { return data->get_value(out); }
|
||||
HRESULT get_virtual(BOOL *out) { return data->get_virtual(out); }
|
||||
HRESULT get_virtualAddress(ULONGLONG *out) { return data->get_virtualAddress(out); }
|
||||
HRESULT get_virtualBaseOffset(DWORD *out) { return data->get_virtualBaseOffset(out); }
|
||||
HRESULT get_volatileType(BOOL *out) { return data->get_volatileType(out); }
|
||||
HRESULT get_classParent(pdb_sym_t *out)
|
||||
{
|
||||
IDiaSymbol *t;
|
||||
HRESULT res = data->get_classParent(&t);
|
||||
return handle_related_symbol(res, t, out);
|
||||
}
|
||||
|
||||
HRESULT get_type(pdb_sym_t *out)
|
||||
{
|
||||
IDiaSymbol *t;
|
||||
HRESULT res = data->get_type(&t);
|
||||
return handle_related_symbol(res, t, out);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------
|
||||
virtual HRESULT get_ordinal(DWORD *) override { return S_FALSE; }
|
||||
|
||||
HRESULT handle_related_symbol(HRESULT fetch_success, IDiaSymbol *t, pdb_sym_t *out)
|
||||
{
|
||||
if ( out == NULL )
|
||||
return S_FALSE;
|
||||
QASSERT(30545, out->whoami() == DIA_PDB_SYM);
|
||||
dia_pdb_sym_t *sym = (dia_pdb_sym_t *)out;
|
||||
sym->set_symbol_data(fetch_success == S_OK ? t : NULL, true);
|
||||
return fetch_success;
|
||||
}
|
||||
|
||||
// careful with this!
|
||||
void steal_data(pdb_sym_t &other)
|
||||
{
|
||||
QASSERT(30541, whoami() == other.whoami());
|
||||
dia_pdb_sym_t &other_dia = (dia_pdb_sym_t &)other;
|
||||
QASSERT(30503, other_dia.own_sym && other_dia.data != NULL && data == NULL);
|
||||
data = other_dia.data;
|
||||
own_sym = true;
|
||||
other_dia.own_sym = false;
|
||||
other_dia.data = NULL;
|
||||
}
|
||||
|
||||
private:
|
||||
dia_pdb_sym_t();
|
||||
|
||||
HRESULT maybe_convert_bstr(qstring *out, HRESULT hr, BSTR *s)
|
||||
{
|
||||
if ( hr == S_OK )
|
||||
{
|
||||
utf16_utf8(out, *s);
|
||||
SysFreeString(*s);
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
};
|
||||
DECLARE_TYPE_AS_MOVABLE(dia_pdb_sym_t);
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
#else // __NT__
|
||||
struct remote_pdb_sym_t : public pdb_sym_t
|
||||
{
|
||||
remote_pdb_sym_t(pdb_access_t *_pdb_access, sym_data_t *_data)
|
||||
: pdb_access(_pdb_access),
|
||||
data(_data)
|
||||
{}
|
||||
|
||||
~remote_pdb_sym_t()
|
||||
{
|
||||
data = NULL;
|
||||
pdb_access = NULL;
|
||||
}
|
||||
|
||||
void set_symbol_data(sym_data_t *s) { data = s; }
|
||||
|
||||
HRESULT get_backEndMajor(DWORD *out) override { return data->get_dword(t_backEndMajor, out); }
|
||||
HRESULT get_baseType(DWORD *out) override { return data->get_dword(t_baseType, out); }
|
||||
HRESULT get_bitPosition(DWORD *out) override { return data->get_dword(t_bitPosition, out); }
|
||||
HRESULT get_callingConvention(DWORD *out) override { return data->get_dword(t_callingConvention, out); }
|
||||
HRESULT get_code(BOOL *out) override { return data->get_bool(t_code, out); }
|
||||
HRESULT get_constructor(BOOL *out) override { return data->get_bool(t_constructor, out); }
|
||||
HRESULT get_isVirtualBaseClass(BOOL *out) override { return data->get_bool(t_isVirtualBaseClass, out); }
|
||||
HRESULT get_constType(BOOL *out) override { return data->get_bool(t_constType, out); }
|
||||
HRESULT get_count(DWORD *out) override { return data->get_dword(t_count, out); }
|
||||
HRESULT get_dataKind(DWORD *out) override { return data->get_dword(t_dataKind, out); }
|
||||
HRESULT get_function(BOOL *out) override { return data->get_bool(t_function, out); }
|
||||
HRESULT get_hasAssignmentOperator(BOOL *out) override { return data->get_bool(t_hasAssignmentOperator, out); }
|
||||
HRESULT get_hasCastOperator(BOOL *out) override { return data->get_bool(t_hasCastOperator, out); }
|
||||
HRESULT get_isStatic(BOOL *out) override { return data->get_bool(t_isStatic, out); }
|
||||
HRESULT get_length(DWORD64 *out) override { return data->get_dword64(t_length, out); }
|
||||
HRESULT get_lexicalParent(pdb_sym_t *out) override;
|
||||
HRESULT get_locationType(DWORD *out) override { return data->get_dword(t_locationType, out); }
|
||||
HRESULT get_machineType(DWORD *out) override { return data->get_dword(t_machineType, out); }
|
||||
HRESULT get_name(qstring *out) override { return data->get_string(t_name, out); }
|
||||
HRESULT get_offset(LONG *out) override { return data->get_dword(t_offset, out); }
|
||||
HRESULT get_registerId(DWORD *out) override { return data->get_dword(t_registerId, out); }
|
||||
HRESULT get_relativeVirtualAddress(DWORD *out) override { return data->get_dword(t_relativeVirtualAddress, out); }
|
||||
HRESULT get_symIndexId(DWORD *out) override { return data->get_dword(t_symIndexId, out); }
|
||||
HRESULT get_symTag(DWORD *out) override { return data->get_dword(t_symTag, out); }
|
||||
HRESULT get_udtKind(DWORD *out) override { return data->get_dword(t_udtKind, out); }
|
||||
HRESULT get_value(VARIANT *out) override { return data->get_variant(t_value, out); }
|
||||
HRESULT get_virtual(BOOL *out) override { return data->get_bool(t_virtual, out); }
|
||||
HRESULT get_virtualAddress(ULONGLONG *out) override { return data->get_ulonglong(t_virtualAddress, out); }
|
||||
HRESULT get_virtualBaseOffset(DWORD *out) override { return data->get_dword(t_virtualBaseOffset, out); }
|
||||
HRESULT get_volatileType(BOOL *out) override { return data->get_bool(t_volatileType, out); }
|
||||
HRESULT get_classParent(pdb_sym_t *out) override;
|
||||
HRESULT get_type(pdb_sym_t *out) override;
|
||||
//------------------------------------------------------------
|
||||
virtual HRESULT get_ordinal(DWORD *) override { return S_FALSE; }
|
||||
|
||||
// careful with this!
|
||||
void steal_data(pdb_sym_t &other) override
|
||||
{
|
||||
QASSERT(30542, whoami() == other.whoami());
|
||||
remote_pdb_sym_t &other_rem = (remote_pdb_sym_t &)other;
|
||||
QASSERT(30492, other_rem.data != NULL && data == NULL);
|
||||
data = other_rem.data;
|
||||
// we don't want to set 'other.data = NULL', because in remote access,
|
||||
// the pdb_sym_t doesn't actually own the data anyway: it's part of
|
||||
// the cache.
|
||||
}
|
||||
|
||||
pdb_sym_id_t whoami(void) override { return REMOTE_PDB_SYM; }
|
||||
bool empty(void) override { return data == NULL; }
|
||||
|
||||
pdb_access_t *pdb_access;
|
||||
sym_data_t *data;
|
||||
|
||||
private:
|
||||
remote_pdb_sym_t();
|
||||
};
|
||||
DECLARE_TYPE_AS_MOVABLE(remote_pdb_sym_t);
|
||||
#endif // !__NT__
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
#define BAD_MACHINE_TYPE ((uint32) -1)
|
||||
|
||||
#define BADSYM ((uint32) -1)
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
struct pdb_lnnum_t
|
||||
{
|
||||
pdb_lnnum_t()
|
||||
: va(BADADDR), length(0),
|
||||
columnNumber(0), columnNumberEnd(0),
|
||||
lineNumber(0), lineNumberEnd(0),
|
||||
file_id(DWORD(-1)), statement(0) {}
|
||||
ULONGLONG va;
|
||||
DWORD length;
|
||||
DWORD columnNumber;
|
||||
DWORD columnNumberEnd;
|
||||
DWORD lineNumber;
|
||||
DWORD lineNumberEnd;
|
||||
DWORD file_id;
|
||||
BOOL statement;
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
typedef qvector<pdb_lnnum_t> pdb_lnnum_vec_t;
|
||||
typedef std::map<int, pdb_lnnum_vec_t> lnmap_t;
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
struct pdb_lnnums_t : pdb_lnnum_vec_t
|
||||
{
|
||||
pdb_lnnums_t() : inited(false) {}
|
||||
|
||||
bool get_item_bounds(rangeset_t *set) const;
|
||||
int get_lnnum() const;
|
||||
int get_colnum() const;
|
||||
int get_end_lnnum() const;
|
||||
int get_end_colnum() const;
|
||||
|
||||
bool inited;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
class pdb_access_t
|
||||
{
|
||||
public:
|
||||
pdb_access_t(const pdbargs_t &args)
|
||||
: pdbargs(args),
|
||||
machine_type((uint32) -1),
|
||||
dia_version(0),
|
||||
base_address(BADADDR),
|
||||
global_sym_id(BADSYM)
|
||||
{
|
||||
}
|
||||
virtual ~pdb_access_t() {}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
struct children_visitor_t
|
||||
{
|
||||
children_visitor_t()
|
||||
: parent(NULL) {}
|
||||
|
||||
virtual HRESULT visit_child(pdb_sym_t &child) = 0;
|
||||
virtual ~children_visitor_t() {}
|
||||
|
||||
pdb_sym_t *parent;
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
struct dummy_visitor_t : public children_visitor_t
|
||||
{
|
||||
virtual HRESULT visit_child(pdb_sym_t &) override { return S_OK; }
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
HRESULT iterate_children(
|
||||
pdb_sym_t &sym,
|
||||
enum SymTagEnum type,
|
||||
children_visitor_t &visitor);
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
virtual HRESULT do_iterate_children(
|
||||
pdb_sym_t &sym,
|
||||
enum SymTagEnum type,
|
||||
children_visitor_t &visitor) = 0;
|
||||
virtual HRESULT iterate_subtags(
|
||||
pdb_sym_t &sym,
|
||||
enum SymTagEnum type,
|
||||
children_visitor_t &visitor);
|
||||
virtual HRESULT load(pdb_sym_t &sym, DWORD id) = 0;
|
||||
|
||||
// source-level debugging-specific
|
||||
virtual HRESULT sip_retrieve_lines_by_va(
|
||||
pdb_lnnums_t *out,
|
||||
ULONGLONG va,
|
||||
ULONGLONG length) = 0;
|
||||
virtual HRESULT sip_retrieve_lines_by_coords(
|
||||
pdb_lnnums_t *out,
|
||||
DWORD file_id,
|
||||
int lnnum,
|
||||
int colnum) = 0;
|
||||
virtual HRESULT sip_iterate_symbols_at_ea(
|
||||
ULONGLONG va,
|
||||
ULONGLONG size,
|
||||
enum SymTagEnum tag,
|
||||
children_visitor_t &visitor) = 0;
|
||||
virtual HRESULT sip_iterate_file_compilands(
|
||||
DWORD file_id,
|
||||
children_visitor_t &visitor) = 0;
|
||||
virtual HRESULT sip_retrieve_file_path(
|
||||
qstring *out,
|
||||
qstring *errbuf,
|
||||
DWORD file_id) = 0;
|
||||
virtual HRESULT sip_retrieve_symbol_files(
|
||||
qvector<DWORD> *out,
|
||||
pdb_sym_t &sym) = 0;
|
||||
virtual HRESULT sip_find_files(
|
||||
qvector<DWORD> *out,
|
||||
const char *filename) = 0; // case insensitive search
|
||||
// /source-level debugging-specific
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
virtual DWORD get_global_symbol_id() const { return global_sym_id; }
|
||||
virtual ea_t get_base_address() const { return base_address; }
|
||||
virtual uint32 get_machine_type() const { return machine_type; }
|
||||
virtual int get_dia_version() const { return dia_version; }
|
||||
|
||||
void set_global_symbol_id(DWORD _global_sym_id) { global_sym_id = _global_sym_id; }
|
||||
void set_machine_type(uint32 _machine_type) { machine_type = _machine_type; }
|
||||
void set_base_address(ea_t _base_address) { base_address = _base_address; }
|
||||
void set_dia_version(int _dia_version) { dia_version = _dia_version; }
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
virtual pdb_sym_t *create_sym(void *data=NULL, bool own=false) = 0;
|
||||
pdb_sym_t *create_sym(DWORD sym_id)
|
||||
{
|
||||
pdb_sym_t *sym = create_sym();
|
||||
if ( load(*sym, sym_id) != S_OK )
|
||||
{
|
||||
qstring err;
|
||||
err.sprnt("Failed loading symbol data for ID %u", sym_id);
|
||||
delete sym;
|
||||
throw pdb_exception_t(err.c_str());
|
||||
}
|
||||
return sym;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
const pdbargs_t &pdbargs;
|
||||
|
||||
private:
|
||||
uint32 machine_type;
|
||||
int dia_version;
|
||||
ea_t base_address;
|
||||
DWORD global_sym_id;
|
||||
DECLARE_UNCOPYABLE(pdb_access_t)
|
||||
};
|
||||
|
||||
|
||||
#endif // PDBACCESS__H
|
||||
399
idasdk76/plugins/pdb/pdblocal.cpp
Normal file
399
idasdk76/plugins/pdb/pdblocal.cpp
Normal file
@@ -0,0 +1,399 @@
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
template <typename T>
|
||||
struct dia_ptr_t
|
||||
{
|
||||
dia_ptr_t() : thing(NULL) {}
|
||||
|
||||
~dia_ptr_t()
|
||||
{
|
||||
if ( thing != NULL )
|
||||
thing->Release();
|
||||
}
|
||||
|
||||
T *thing;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
HRESULT local_pdb_access_t::_do_iterate_symbols_enumerator(
|
||||
IDiaEnumSymbols *sym_enum,
|
||||
children_visitor_t &visitor)
|
||||
{
|
||||
std::set<DWORD> seen;
|
||||
HRESULT hr = S_OK;
|
||||
while ( true )
|
||||
{
|
||||
ULONG celt = 0;
|
||||
IDiaSymbol *pChild = NULL;
|
||||
hr = sym_enum->Next(1, &pChild, &celt);
|
||||
if ( FAILED(hr) || celt != 1 )
|
||||
{
|
||||
hr = S_OK; // end of enumeration
|
||||
break;
|
||||
}
|
||||
pdb_sym_t *child = create_sym(pChild, true);
|
||||
pdb_sym_janitor_t janitor_pType(child);
|
||||
DWORD sym_id;
|
||||
hr = child->get_symIndexId(&sym_id);
|
||||
if ( hr != S_OK )
|
||||
break;
|
||||
// It seems we can, in some cases, iterate over the
|
||||
// same child more than once.
|
||||
// Fortunately, it appears to be the same symbol data;
|
||||
// and not another symbol w/ the same ID
|
||||
// See also: sip_iterate_symbols_at_ea()
|
||||
if ( seen.insert(sym_id).second )
|
||||
{
|
||||
hr = visitor.visit_child(*child);
|
||||
if ( FAILED(hr) )
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
HRESULT local_pdb_access_t::safe_iterate_children(
|
||||
pdb_sym_t &sym,
|
||||
enum SymTagEnum type,
|
||||
children_visitor_t &visitor)
|
||||
{
|
||||
HRESULT hr = E_FAIL;
|
||||
IDiaEnumSymbols *pEnumSymbols;
|
||||
try
|
||||
{
|
||||
QASSERT(30536, sym.whoami() == DIA_PDB_SYM);
|
||||
dia_pdb_sym_t &diasym = (dia_pdb_sym_t &)sym;
|
||||
hr = dia_session->findChildren(diasym.data, type, NULL, nsNone, &pEnumSymbols);
|
||||
if ( hr == S_OK )
|
||||
{
|
||||
hr = _do_iterate_symbols_enumerator(pEnumSymbols, visitor);
|
||||
pEnumSymbols->Release();
|
||||
}
|
||||
}
|
||||
catch ( const std::bad_alloc & )
|
||||
{
|
||||
// try to free some memory before quitting (and saving the idb)
|
||||
delete this;
|
||||
nomem("pdb");
|
||||
}
|
||||
catch ( const std::exception &e )
|
||||
{
|
||||
error("Unhandled C++ exception: %s", e.what());
|
||||
}
|
||||
catch ( ... )
|
||||
{
|
||||
error("Unhandled C++ exception!");
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
HRESULT local_pdb_access_t::do_iterate_children(
|
||||
pdb_sym_t &sym,
|
||||
enum SymTagEnum type,
|
||||
children_visitor_t &visitor)
|
||||
{
|
||||
int code;
|
||||
HRESULT hr = E_FAIL;
|
||||
__try
|
||||
{
|
||||
hr = safe_iterate_children(sym, type, visitor);
|
||||
}
|
||||
__except ( code=GetExceptionCode(), EXCEPTION_EXECUTE_HANDLER )
|
||||
{
|
||||
// complain to the user
|
||||
ask_for_feedback(
|
||||
"%s: %s\n"
|
||||
"Is the corresponding PDB file valid?",
|
||||
pdbargs.input_path.c_str(),
|
||||
winerr(code));
|
||||
|
||||
// we may arrive here because we ran out of memory
|
||||
// try to free some memory before quitting (and saving the idb)
|
||||
delete this;
|
||||
error(NULL); // and die... this will save the idb
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
HRESULT local_pdb_access_t::load(pdb_sym_t &pdbsym, DWORD id)
|
||||
{
|
||||
IDiaSymbol *dia_sym;
|
||||
HRESULT hr = dia_session->symbolById(id, &dia_sym);
|
||||
if ( hr == S_OK )
|
||||
{
|
||||
QASSERT(30543, pdbsym.whoami() == DIA_PDB_SYM);
|
||||
dia_pdb_sym_t &sym = (dia_pdb_sym_t &)pdbsym;
|
||||
sym.set_symbol_data(dia_sym, true);
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
HRESULT local_pdb_access_t::_copy_line_numbers(
|
||||
pdb_lnnums_t *out,
|
||||
IDiaEnumLineNumbers *enumerator) const
|
||||
{
|
||||
LONG count = 0;
|
||||
HRESULT hr = enumerator->get_Count(&count);
|
||||
if ( hr == S_OK )
|
||||
{
|
||||
IDiaLineNumber *lines[64];
|
||||
ULONG got = 0;
|
||||
for ( LONG i=0; i < count; i += got )
|
||||
{
|
||||
// Fetch many line number information at once
|
||||
enumerator->Next(qnumber(lines), lines, &got);
|
||||
if ( got == 0 )
|
||||
break;
|
||||
|
||||
for ( ULONG j=0; j < got; j++ )
|
||||
{
|
||||
IDiaLineNumber *l = lines[j];
|
||||
pdb_lnnum_t &lo = out->push_back();
|
||||
l->get_virtualAddress(&lo.va);
|
||||
l->get_length(&lo.length);
|
||||
l->get_columnNumber(&lo.columnNumber);
|
||||
l->get_columnNumberEnd(&lo.columnNumberEnd);
|
||||
l->get_lineNumber(&lo.lineNumber);
|
||||
l->get_lineNumberEnd(&lo.lineNumberEnd);
|
||||
l->get_statement(&lo.statement);
|
||||
IDiaSourceFile *f = NULL;
|
||||
if ( l->get_sourceFile(&f) == S_OK )
|
||||
{
|
||||
f->get_uniqueId(&lo.file_id);
|
||||
f->Release();
|
||||
}
|
||||
lines[j]->Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
HRESULT local_pdb_access_t::sip_retrieve_lines_by_va(
|
||||
pdb_lnnums_t *out,
|
||||
ULONGLONG va,
|
||||
ULONGLONG length)
|
||||
{
|
||||
dia_ptr_t<IDiaEnumLineNumbers> pEnumLineNumbers;
|
||||
HRESULT hr = dia_session->findLinesByVA(va, length, &pEnumLineNumbers.thing);
|
||||
if ( hr == S_OK )
|
||||
hr = _copy_line_numbers(out, pEnumLineNumbers.thing);
|
||||
return hr;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
HRESULT local_pdb_access_t::sip_retrieve_lines_by_coords(
|
||||
pdb_lnnums_t *out,
|
||||
DWORD file_id,
|
||||
int lnnum,
|
||||
int colnum)
|
||||
{
|
||||
dia_ptr_t<IDiaSourceFile> pFile;
|
||||
HRESULT hr = dia_session->findFileById(file_id, &pFile.thing);
|
||||
if ( FAILED(hr) )
|
||||
return hr;
|
||||
|
||||
dia_ptr_t<IDiaEnumSymbols> pEnumSymbols;
|
||||
hr = pFile.thing->get_compilands(&pEnumSymbols.thing);
|
||||
if ( FAILED(hr) )
|
||||
return hr;
|
||||
|
||||
while ( true )
|
||||
{
|
||||
ULONG got = 0;
|
||||
IDiaSymbol *compiland;
|
||||
pEnumSymbols.thing->Next(1, &compiland, &got);
|
||||
if ( got == 0 )
|
||||
break;
|
||||
|
||||
dia_ptr_t<IDiaEnumLineNumbers> pEnumLineNumbers;
|
||||
HRESULT hr2;
|
||||
if ( lnnum == 0 )
|
||||
hr2 = dia_session->findLines(
|
||||
compiland,
|
||||
pFile.thing,
|
||||
&pEnumLineNumbers.thing);
|
||||
else
|
||||
hr2 = dia_session->findLinesByLinenum(
|
||||
compiland,
|
||||
pFile.thing,
|
||||
lnnum,
|
||||
colnum,
|
||||
&pEnumLineNumbers.thing);
|
||||
compiland->Release();
|
||||
|
||||
if ( hr == S_OK )
|
||||
_copy_line_numbers(out, pEnumLineNumbers.thing);
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
HRESULT local_pdb_access_t::sip_iterate_symbols_at_ea(
|
||||
ULONGLONG va,
|
||||
ULONGLONG size,
|
||||
enum SymTagEnum tag,
|
||||
children_visitor_t &visitor)
|
||||
{
|
||||
// See also: _do_iterate_symbols_enumerator
|
||||
std::set<DWORD> seen;
|
||||
|
||||
ea_t cur = va;
|
||||
while ( true )
|
||||
{
|
||||
if ( cur >= va + size )
|
||||
break;
|
||||
|
||||
ea_t old = cur;
|
||||
qnotused(old);
|
||||
|
||||
LONG disp;
|
||||
IDiaSymbol *sym = NULL;
|
||||
HRESULT hr = dia_session->findSymbolByVAEx(cur, tag, &sym, &disp);
|
||||
if ( FAILED(hr) || sym == NULL )
|
||||
break;
|
||||
|
||||
// perform all get_*'s on 'sym' _before_ the visitor is called: it might
|
||||
// very well 'steal' the symbol & destroy it in case it's not needed.
|
||||
// (see source_items_vec_builder_t::visit_child())
|
||||
pdb_sym_t *psym = create_sym(sym, true);
|
||||
pdb_sym_janitor_t janitor_psym(psym);
|
||||
DWORD sym_id;
|
||||
hr = psym->get_symIndexId(&sym_id);
|
||||
if ( hr != S_OK )
|
||||
break;
|
||||
|
||||
ULONGLONG length = 0;
|
||||
sym->get_length(&length);
|
||||
|
||||
if ( seen.insert(sym_id).second )
|
||||
{
|
||||
hr = visitor.visit_child(*psym);
|
||||
if ( FAILED(hr) )
|
||||
break;
|
||||
}
|
||||
|
||||
cur -= disp;
|
||||
cur += length;
|
||||
|
||||
QASSERT(30169, cur > old); // to avoid endless loops - i do not know if they are possible
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
HRESULT local_pdb_access_t::sip_iterate_file_compilands(
|
||||
DWORD file_id,
|
||||
children_visitor_t &visitor)
|
||||
{
|
||||
dia_ptr_t<IDiaSourceFile> pFile;
|
||||
HRESULT hr = dia_session->findFileById(file_id, &pFile.thing);
|
||||
if ( FAILED(hr) )
|
||||
return hr;
|
||||
|
||||
dia_ptr_t<IDiaEnumSymbols> pEnumSymbols;
|
||||
hr = pFile.thing->get_compilands(&pEnumSymbols.thing);
|
||||
if ( hr == S_OK )
|
||||
hr = _do_iterate_symbols_enumerator(pEnumSymbols.thing, visitor);
|
||||
return hr;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
HRESULT local_pdb_access_t::sip_retrieve_file_path(
|
||||
qstring *out,
|
||||
qstring *errbuf,
|
||||
DWORD file_id)
|
||||
{
|
||||
dia_ptr_t<IDiaSourceFile> pFile;
|
||||
HRESULT hr = dia_session->findFileById(file_id, &pFile.thing);
|
||||
if ( hr == S_OK )
|
||||
{
|
||||
BSTR path;
|
||||
hr = pFile.thing->get_fileName(&path);
|
||||
if ( hr == S_OK )
|
||||
{
|
||||
utf16_utf8(out, path);
|
||||
SysFreeString(path);
|
||||
}
|
||||
}
|
||||
|
||||
if ( FAILED(hr) )
|
||||
{
|
||||
if ( errbuf != NULL )
|
||||
*errbuf = winerr(hr);
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
HRESULT local_pdb_access_t::_copy_files_ids(
|
||||
qvector<DWORD> *out,
|
||||
IDiaEnumSourceFiles *enumerator) const
|
||||
{
|
||||
ULONG celt = 0;
|
||||
IDiaSourceFile *file = NULL;
|
||||
while ( enumerator->Next(1, &file, &celt) == S_OK && celt > 0 )
|
||||
{
|
||||
DWORD file_id;
|
||||
if ( file->get_uniqueId(&file_id) == S_OK )
|
||||
out->push_back(file_id);
|
||||
file->Release();
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
HRESULT local_pdb_access_t::sip_retrieve_symbol_files(
|
||||
qvector<DWORD> *out,
|
||||
pdb_sym_t &sym)
|
||||
{
|
||||
// Retrieve source file name associated with the current symbol
|
||||
QASSERT(30537, sym.whoami() == DIA_PDB_SYM);
|
||||
dia_pdb_sym_t &diasym = (dia_pdb_sym_t &)sym;
|
||||
BSTR path;
|
||||
HRESULT hr = diasym.data->get_sourceFileName(&path);
|
||||
if ( hr == S_OK ) // cannot use SUCCEEDED(hr) because S_OK means success
|
||||
{
|
||||
dia_ptr_t<IDiaEnumSourceFiles> pEnumSourceFiles;
|
||||
hr = dia_session->findFile(NULL, path, nsfFNameExt, &pEnumSourceFiles.thing);
|
||||
SysFreeString(path);
|
||||
|
||||
if ( hr == S_OK )
|
||||
_copy_files_ids(out, pEnumSourceFiles.thing);
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
HRESULT local_pdb_access_t::sip_find_files(
|
||||
qvector<DWORD> *out,
|
||||
const char *filename)
|
||||
{
|
||||
qwstring fnamebuf;
|
||||
wchar16_t *fname = NULL;
|
||||
if ( filename != NULL )
|
||||
{
|
||||
qstring fnametmp = filename;
|
||||
utf8_utf16(&fnamebuf, &fnametmp[0]);
|
||||
fname = fnamebuf.begin();
|
||||
}
|
||||
|
||||
dia_ptr_t<IDiaEnumSourceFiles> pEnumSourceFiles;
|
||||
HRESULT hr = dia_session->findFile(
|
||||
NULL,
|
||||
fname,
|
||||
nsfFNameExt | nsfCaseInsensitive,
|
||||
&pEnumSourceFiles.thing);
|
||||
|
||||
if ( hr == S_OK )
|
||||
_copy_files_ids(out, pEnumSourceFiles.thing);
|
||||
|
||||
return hr;
|
||||
}
|
||||
116
idasdk76/plugins/pdb/pdblocal.hpp
Normal file
116
idasdk76/plugins/pdb/pdblocal.hpp
Normal file
@@ -0,0 +1,116 @@
|
||||
|
||||
#ifndef PDBLOCAL_HPP
|
||||
#define PDBLOCAL_HPP
|
||||
|
||||
// The PDB related code that works on Windows and uses DIA
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
class local_pdb_access_t : public pdb_access_t
|
||||
{
|
||||
public:
|
||||
local_pdb_access_t(
|
||||
const pdbargs_t &args,
|
||||
IDiaDataSource *pSource,
|
||||
IDiaSession *pSession,
|
||||
IDiaSymbol *pGlobal)
|
||||
: pdb_access_t(args),
|
||||
dia_source(pSource),
|
||||
dia_session(pSession),
|
||||
dia_global(pGlobal)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~local_pdb_access_t()
|
||||
{
|
||||
#define RELEASE(thing) do { if ( thing != NULL ) { (thing)->Release(); thing = NULL; } } while ( false )
|
||||
RELEASE(dia_global);
|
||||
RELEASE(dia_session);
|
||||
RELEASE(dia_source);
|
||||
#undef RELEASE
|
||||
set_global_symbol_id(BADSYM);
|
||||
}
|
||||
|
||||
HRESULT init()
|
||||
{
|
||||
DWORD id;
|
||||
HRESULT hr = dia_global->get_symIndexId(&id);
|
||||
if ( hr != S_OK )
|
||||
return hr;
|
||||
set_global_symbol_id(id);
|
||||
|
||||
DWORD64 load_addr;
|
||||
hr = dia_session->get_loadAddress(&load_addr);
|
||||
if ( hr != S_OK )
|
||||
return hr;
|
||||
set_base_address(load_addr);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
virtual HRESULT do_iterate_children(
|
||||
pdb_sym_t &sym,
|
||||
enum SymTagEnum type,
|
||||
children_visitor_t &visitor) override;
|
||||
virtual HRESULT load(pdb_sym_t &sym, DWORD id) override;
|
||||
|
||||
virtual HRESULT sip_retrieve_lines_by_va(
|
||||
pdb_lnnums_t *out,
|
||||
ULONGLONG va,
|
||||
ULONGLONG length) override;
|
||||
virtual HRESULT sip_retrieve_lines_by_coords(
|
||||
pdb_lnnums_t *out,
|
||||
DWORD file_id,
|
||||
int lnnum,
|
||||
int colnum) override;
|
||||
virtual HRESULT sip_iterate_symbols_at_ea(
|
||||
ULONGLONG va,
|
||||
ULONGLONG size,
|
||||
enum SymTagEnum tag,
|
||||
children_visitor_t &visitor) override;
|
||||
virtual HRESULT sip_iterate_file_compilands(
|
||||
DWORD file_id,
|
||||
children_visitor_t &visitor) override;
|
||||
virtual HRESULT sip_retrieve_file_path(
|
||||
qstring *out,
|
||||
qstring *errbuf,
|
||||
DWORD file_id) override;
|
||||
virtual HRESULT sip_retrieve_symbol_files(
|
||||
qvector<DWORD> *out,
|
||||
pdb_sym_t &sym) override;
|
||||
virtual HRESULT sip_find_files(
|
||||
qvector<DWORD> *out,
|
||||
const char *name) override;
|
||||
|
||||
virtual pdb_sym_t *create_sym(void *data, bool own) override
|
||||
{
|
||||
IDiaSymbol *sym = (IDiaSymbol *)data;
|
||||
return new dia_pdb_sym_t(this, sym, own);
|
||||
}
|
||||
pdb_sym_t *create_sym(DWORD sym_id) { return pdb_access_t::create_sym(sym_id); }
|
||||
|
||||
IDiaDataSource *dia_source;
|
||||
IDiaSession *dia_session;
|
||||
IDiaSymbol *dia_global;
|
||||
|
||||
private:
|
||||
HRESULT safe_iterate_children(
|
||||
pdb_sym_t &sym,
|
||||
enum SymTagEnum type,
|
||||
children_visitor_t &visitor);
|
||||
HRESULT _do_iterate_symbols_enumerator(
|
||||
IDiaEnumSymbols *sym_enum,
|
||||
children_visitor_t &visitor);
|
||||
|
||||
HRESULT _copy_line_numbers(
|
||||
pdb_lnnums_t *out,
|
||||
IDiaEnumLineNumbers *enumerator) const;
|
||||
|
||||
HRESULT _copy_files_ids(
|
||||
qvector<DWORD> *out,
|
||||
IDiaEnumSourceFiles *enumerator) const;
|
||||
|
||||
DECLARE_UNCOPYABLE(local_pdb_access_t)
|
||||
};
|
||||
|
||||
|
||||
#endif // PDBLOCAL_HPP
|
||||
898
idasdk76/plugins/pdb/pdbremote.cpp
Normal file
898
idasdk76/plugins/pdb/pdbremote.cpp
Normal file
@@ -0,0 +1,898 @@
|
||||
|
||||
#include <pro.h>
|
||||
|
||||
#include "pdbremote.hpp"
|
||||
#include "varser.hpp"
|
||||
|
||||
// Since we're using the win32 local stup debugger at the moment,
|
||||
// this is necessary.
|
||||
#include <dbg.hpp>
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
bool is_win32_remote_debugger_loaded()
|
||||
{
|
||||
return dbg != NULL && dbg->is_remote() && streq(dbg->name, "win32");
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
HRESULT remote_pdb_sym_t::get_classParent(pdb_sym_t *out)
|
||||
{
|
||||
DWORD parent_id;
|
||||
HRESULT hr = data->get_dword(t_classParentId, &parent_id);
|
||||
if ( hr == S_OK )
|
||||
hr = pdb_access->load(*out, parent_id);
|
||||
return hr;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
HRESULT remote_pdb_sym_t::get_type(pdb_sym_t *out)
|
||||
{
|
||||
DWORD type_id;
|
||||
HRESULT hr = data->get_dword(t_typeId, &type_id);
|
||||
if ( hr == S_OK )
|
||||
hr = pdb_access->load(*out, type_id);
|
||||
return hr;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
HRESULT remote_pdb_sym_t::get_lexicalParent(pdb_sym_t *out)
|
||||
{
|
||||
DWORD lparent_id;
|
||||
HRESULT hr = data->get_dword(t_lexicalParentId, &lparent_id);
|
||||
if ( hr == S_OK )
|
||||
hr = pdb_access->load(*out, lparent_id);
|
||||
return hr;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
const uint32 sym_data_t::sizes[] =
|
||||
{
|
||||
sizeof(BOOL),
|
||||
sizeof(DWORD),
|
||||
sizeof(DWORD64),
|
||||
sizeof(char *),
|
||||
sizeof(LONG),
|
||||
sizeof(ULONGLONG),
|
||||
sizeof(VARIANT)
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
sym_data_t::sym_data_t(
|
||||
token_mask_t _tokens,
|
||||
const uchar *buf,
|
||||
size_t bufsize,
|
||||
packing_info_t _packing,
|
||||
bool *_warned)
|
||||
: present(_tokens),
|
||||
warned(_warned)
|
||||
{
|
||||
memset(counters, 0, sizeof(counters));
|
||||
memset(children_infos, 0, sizeof(children_infos));
|
||||
|
||||
if ( _packing == SYMDAT_PACKED )
|
||||
{
|
||||
const uchar *ptr = buf;
|
||||
const uchar *const end = buf + bufsize;
|
||||
for ( uint64 bit = t_start; bit != t_end; bit <<= 1 )
|
||||
{
|
||||
sym_token_t token = sym_token_t(bit);
|
||||
if ( !token_present(token) )
|
||||
continue;
|
||||
|
||||
if ( is_sym_token_bool(token) )
|
||||
{
|
||||
counters[t_bool]++;
|
||||
uint8 tmp = unpack_db(&ptr, end);
|
||||
data.append(&tmp, sizeof(tmp));
|
||||
}
|
||||
else if ( is_sym_token_dword(token) )
|
||||
{
|
||||
counters[t_dword]++;
|
||||
uint32 tmp = unpack_dd(&ptr, end);
|
||||
data.append(&tmp, sizeof(tmp));
|
||||
}
|
||||
else if ( is_sym_token_dword64(token) )
|
||||
{
|
||||
counters[t_dword64]++;
|
||||
uint64 tmp = unpack_dq(&ptr, end);
|
||||
data.append(&tmp, sizeof(tmp));
|
||||
}
|
||||
else if ( is_sym_token_string(token) )
|
||||
{
|
||||
counters[t_string]++;
|
||||
char *tmp = qstrdup(unpack_str(&ptr, end));
|
||||
data.append(&tmp, sizeof(tmp));
|
||||
}
|
||||
else if ( is_sym_token_long(token) )
|
||||
{
|
||||
counters[t_long]++;
|
||||
LONG tmp = unpack_dd(&ptr, end);
|
||||
data.append(&tmp, sizeof(tmp));
|
||||
}
|
||||
else if ( is_sym_token_ulonglong(token) )
|
||||
{
|
||||
counters[t_ulonglong]++;
|
||||
ULONGLONG tmp = unpack_dq(&ptr, end);
|
||||
data.append(&tmp, sizeof(tmp));
|
||||
}
|
||||
else if ( is_sym_token_variant(token) )
|
||||
{
|
||||
counters[t_variant]++;
|
||||
VARIANT var;
|
||||
if ( varser_t::deserialize(var, &ptr, end) )
|
||||
{
|
||||
data.append(&var, sizeof(var));
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( !*warned )
|
||||
{
|
||||
warning("The PDB file contains VARIANT items that cannot be deserialized.");
|
||||
*warned = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
INTERR(30200);
|
||||
}
|
||||
}
|
||||
|
||||
QASSERT(30201, data.size() == counters[t_bool] * sizes[t_bool]
|
||||
+ counters[t_dword] * sizes[t_dword]
|
||||
+ counters[t_dword64] * sizes[t_dword64]
|
||||
+ counters[t_string] * sizes[t_string]
|
||||
+ counters[t_long] * sizes[t_long]
|
||||
+ counters[t_ulonglong] * sizes[t_ulonglong]
|
||||
+ counters[t_variant] * sizes[t_variant]);
|
||||
QASSERT(30202, ptr == end);
|
||||
}
|
||||
else
|
||||
{
|
||||
data.append(buf, bufsize);
|
||||
// Not supported yet. All that's left to do
|
||||
// is count the types (counters[]), though.
|
||||
INTERR(30203);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
sym_data_t::~sym_data_t()
|
||||
{
|
||||
for ( int i = 0; i < SymTagMax; i++ )
|
||||
{
|
||||
children_t &children = children_infos[i];
|
||||
if ( children.ids != NULL )
|
||||
{
|
||||
qfree(children.ids);
|
||||
children.ids = NULL;
|
||||
children.cnt = 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint8 nstring = counters[t_string];
|
||||
if ( nstring > 0 )
|
||||
{
|
||||
char **cur_str_ptr = (char **)string_ptr(t_string_start);
|
||||
for ( uint8 i = 0; i < nstring; i++, cur_str_ptr++ )
|
||||
qfree(*cur_str_ptr);
|
||||
}
|
||||
|
||||
uint8 nvariant = counters[t_variant];
|
||||
if ( nvariant > 0 )
|
||||
{
|
||||
VARIANT *cur_variant_ptr = (VARIANT *)variant_ptr(t_variant_start);
|
||||
for ( uint8 i = 0; i < nvariant; i++, cur_variant_ptr++ )
|
||||
if ( cur_variant_ptr->vt == VT_LPSTR )
|
||||
qfree(cur_variant_ptr->punkVal);
|
||||
}
|
||||
|
||||
warned = nullptr;
|
||||
}
|
||||
|
||||
|
||||
#define READ_IF_FOUND(type, fun) \
|
||||
const type *ptr = fun##_ptr(token); \
|
||||
if ( ptr == NULL ) \
|
||||
{ \
|
||||
return S_FALSE; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
*out = *ptr; \
|
||||
return S_OK; \
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
HRESULT sym_data_t::get_bool(sym_token_t token, BOOL *out) const
|
||||
{
|
||||
READ_IF_FOUND(BOOL, bool)
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
HRESULT sym_data_t::get_dword(sym_token_t token, DWORD *out) const
|
||||
{
|
||||
READ_IF_FOUND(DWORD, dword)
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
HRESULT sym_data_t::get_dword64(sym_token_t token, DWORD64 *out) const
|
||||
{
|
||||
READ_IF_FOUND(DWORD64, dword64)
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
HRESULT sym_data_t::get_string(sym_token_t token, qstring *out) const
|
||||
{
|
||||
READ_IF_FOUND(char *, string)
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
HRESULT sym_data_t::get_dword(sym_token_t token, LONG *out) const
|
||||
{
|
||||
READ_IF_FOUND(LONG, long)
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
HRESULT sym_data_t::get_ulonglong(sym_token_t token, ULONGLONG *out) const
|
||||
{
|
||||
READ_IF_FOUND(ULONGLONG, uint64)
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
HRESULT sym_data_t::get_variant(sym_token_t token, VARIANT *out) const
|
||||
{
|
||||
READ_IF_FOUND(VARIANT, variant)
|
||||
}
|
||||
|
||||
#undef READ_IF_FOUND
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
const void *sym_data_t::any_ptr(sym_token_t token, sym_token_t start, sym_token_t end) const
|
||||
{
|
||||
if ( !token_present(token) )
|
||||
return NULL;
|
||||
|
||||
static const sym_token_t ends[] =
|
||||
{
|
||||
t_bool_end,
|
||||
t_dword_end,
|
||||
t_dword64_end,
|
||||
t_string_end,
|
||||
t_long_end,
|
||||
t_ulonglong_end,
|
||||
t_variant_end,
|
||||
};
|
||||
CASSERT(qnumber(ends) == qnumber(counters));
|
||||
CASSERT(qnumber(sizes) == qnumber(counters));
|
||||
|
||||
// count how many bytes we have to skip and determine the type size
|
||||
uint32 type_size = 0;
|
||||
const uchar *ptr = data.begin();
|
||||
for ( int i=0; i < qnumber(ends); i++ )
|
||||
{
|
||||
if ( token <= ends[i] )
|
||||
{
|
||||
type_size = sizes[i];
|
||||
break;
|
||||
}
|
||||
ptr += counters[i] * sizes[i];
|
||||
}
|
||||
QASSERT(30204, type_size != 0);
|
||||
|
||||
// how many tokens of our type we have to skip?
|
||||
uint32 bit;
|
||||
for ( bit = start; bit <= end; bit <<= 1 )
|
||||
{
|
||||
sym_token_t t = sym_token_t(bit);
|
||||
if ( token_present(t) )
|
||||
{
|
||||
if ( t == token )
|
||||
return ptr;
|
||||
ptr += type_size;
|
||||
}
|
||||
}
|
||||
return NULL; // did not find the requested token
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
remote_pdb_access_t::~remote_pdb_access_t()
|
||||
{
|
||||
typedef std::map<DWORD,sym_data_t*>::iterator iter;
|
||||
for ( iter it = cache.begin(), end = cache.end(); it != end; it++ )
|
||||
delete it->second;
|
||||
|
||||
close_connection();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void remote_pdb_access_t::close_connection()
|
||||
{
|
||||
if ( remote_session_id > 0 )
|
||||
{
|
||||
bytevec_t dummy;
|
||||
perform_op(WIN32_IOCTL_PDB_CLOSE, dummy, NULL);
|
||||
remote_session_id = -1;
|
||||
}
|
||||
|
||||
if ( !was_connected && dbg != NULL )
|
||||
dbg->term_debugger();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// load and connect to a remote win32 debugger, if necessary
|
||||
bool remote_pdb_access_t::load_win32_debugger(void)
|
||||
{
|
||||
was_connected = false;
|
||||
if ( dbg != NULL && !is_win32_remote_debugger_loaded() )
|
||||
{
|
||||
// a debugger is loaded, but it's not a remote win32
|
||||
warning("Loading PDB symbols requires a remote win32 debugger. "
|
||||
"Please stop the current debugging session and try again.");
|
||||
return false;
|
||||
}
|
||||
if ( get_process_state() != DSTATE_NOTASK )
|
||||
{
|
||||
// the debugger is already connected
|
||||
was_connected = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
netnode pdbnode(PDB_NODE_NAME);
|
||||
pdbnode.altset(PDB_LOADING_WIN32_DBG, true);
|
||||
bool win32_dbg_loaded = load_debugger("win32", true) && dbg != NULL;
|
||||
pdbnode.altdel(PDB_LOADING_WIN32_DBG);
|
||||
|
||||
if ( !win32_dbg_loaded )
|
||||
{
|
||||
warning("Could not load remote Win32 debugger.");
|
||||
return false;
|
||||
}
|
||||
|
||||
qstring server;
|
||||
server = host[0] != '\0' ? host : "localhost";
|
||||
|
||||
qstring pass;
|
||||
if ( pwd != NULL )
|
||||
pass = pwd;
|
||||
|
||||
qstring dbg_errbuf;
|
||||
while ( !dbg->init_debugger(server.c_str(), port, pass.c_str(), &dbg_errbuf) )
|
||||
{
|
||||
if ( batch ) // avoid endless (and useless) loop in batch mode
|
||||
return false;
|
||||
if ( !dbg_errbuf.empty() )
|
||||
msg("%s\n", dbg_errbuf.begin());
|
||||
// hrw
|
||||
const char *winremote = inf_is_64bit() ? "win64_remote64.exe" : "win32_remote.exe";
|
||||
qstring formstr;
|
||||
formstr.sprnt(
|
||||
"Remote PDB server\n"
|
||||
"In order to load PDB information, IDA requires a running %s debugger server\n"
|
||||
"running on a Windows host, but it could not connect to the %s debugger\n"
|
||||
"at the current specified address.\n"
|
||||
"Please make sure that %s is running there.\n\n"
|
||||
"<#Name of the remote host#~H~ostname :q:1023:30::> <#Remote port number#Po~r~t:D::8::>\n"
|
||||
"<#Password for the remote host#Pass~w~ord :q:1023:30::>\n"
|
||||
"Hint: to change this permanently, edit pdb.cfg.\n\n",
|
||||
winremote, winremote, winremote);
|
||||
uval_t sport = port;
|
||||
int r = ask_form(formstr.c_str(), &server, &sport, &pass);
|
||||
if ( r != 1 )
|
||||
return false;
|
||||
port = sport;
|
||||
}
|
||||
msg("PDB: successfully connected to %s\n", server.c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
#define REPORT_ERROR(Msg, Rc) \
|
||||
do \
|
||||
{ \
|
||||
qfree(outbuf); \
|
||||
qstrncpy(errbuf, Msg, sizeof(errbuf)); \
|
||||
return Rc; \
|
||||
} while ( false )
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
HRESULT remote_pdb_access_t::open_connection()
|
||||
{
|
||||
// Load win32 debugger (FIXME: Should just use an RPC client, not a full debugger!)
|
||||
if ( !load_win32_debugger() )
|
||||
return S_FALSE;
|
||||
|
||||
// Init remote.
|
||||
bytevec_t oper;
|
||||
compiler_info_t cc;
|
||||
inf_get_cc(&cc);
|
||||
oper.append(&cc, sizeof(cc));
|
||||
oper.pack_str(pdbargs.pdb_path);
|
||||
oper.pack_str(pdbargs.input_path);
|
||||
oper.append(&pdbargs.pdb_sign, sizeof(pdbargs.pdb_sign));
|
||||
oper.pack_str(pdbargs.spath);
|
||||
oper.pack_ea64(get_base_address());
|
||||
oper.pack_dd(pdbargs.flags);
|
||||
|
||||
void *outbuf = NULL;
|
||||
ssize_t outsize = 0;
|
||||
ioctl_pdb_code_t rc = send_ioctl(
|
||||
WIN32_IOCTL_PDB_OPEN,
|
||||
oper.begin(), oper.size(), &outbuf, &outsize);
|
||||
if ( rc != pdb_ok || outsize < 1 )
|
||||
REPORT_ERROR(
|
||||
"PDB symbol extraction is not supported by the remote server",
|
||||
E_FAIL);
|
||||
|
||||
// remote PDB session has become active
|
||||
bytevec_t sidbuf;
|
||||
{
|
||||
const uchar *ptr = (const uchar *) outbuf;
|
||||
const uchar *const end = ptr + outsize;
|
||||
remote_session_id = unpack_dd(&ptr, end);
|
||||
QASSERT(30493, remote_session_id > 0);
|
||||
sidbuf.pack_dd(remote_session_id);
|
||||
}
|
||||
|
||||
// now, do the polling game.
|
||||
bool done = false;
|
||||
while ( !done )
|
||||
{
|
||||
qfree(outbuf);
|
||||
outbuf = NULL;
|
||||
qsleep(100);
|
||||
user_cancelled(); // refresh the output window
|
||||
rc = send_ioctl(
|
||||
WIN32_IOCTL_PDB_OPERATION_COMPLETE,
|
||||
sidbuf.begin(), sidbuf.size(),
|
||||
&outbuf, &outsize);
|
||||
if ( rc != pdb_ok || outsize <= 0 )
|
||||
REPORT_ERROR(
|
||||
"remote server reported error while opening PDB",
|
||||
E_FAIL);
|
||||
const uchar *ptr = (const uchar *)outbuf;
|
||||
const uchar *const end = ptr + outsize;
|
||||
pdb_op_completion_t status = pdb_op_completion_t(unpack_dd(&ptr, end));
|
||||
done = true; // only 'not complete' status will make us continue.
|
||||
switch ( status )
|
||||
{
|
||||
case pdb_op_not_complete:
|
||||
done = false;
|
||||
break;
|
||||
case pdb_op_complete:
|
||||
{
|
||||
set_global_symbol_id(unpack_dd(&ptr, end));
|
||||
set_machine_type(unpack_dd(&ptr, end));
|
||||
set_dia_version(unpack_dd(&ptr, end));
|
||||
const char *fname = unpack_str(&ptr, end);
|
||||
// TODO The printed path is wrong (test with pc_gdb_notepad.exe).
|
||||
msg("PDB: opened \"%s\"\n", fname);
|
||||
}
|
||||
break;
|
||||
case pdb_op_failure:
|
||||
{
|
||||
const char *errmsg = unpack_str(&ptr, end);
|
||||
REPORT_ERROR(errmsg, E_FAIL);
|
||||
// if opening pdb fails, win32_remote closes the MSDIA pdb
|
||||
// session automatically.
|
||||
remote_session_id = -1; //-V779 Unreachable code detected
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
qfree(outbuf);
|
||||
|
||||
return remote_session_id > 0 ? S_OK : E_FAIL;
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
ioctl_pdb_code_t remote_pdb_access_t::send_ioctl(
|
||||
int fn,
|
||||
const void *buf,
|
||||
size_t size,
|
||||
void **outbuf,
|
||||
ssize_t *outsz)
|
||||
{
|
||||
if ( dbg == NULL )
|
||||
return pdb_error;
|
||||
|
||||
deb(IDA_DEBUG_DEBUGGER, "PDB: send_ioctl(fn=%d, size=%" FMT_Z ")\n", fn, size);
|
||||
// internal_ioctl() will either send the request to the debugger thread if
|
||||
// it exists (i.e., we are in a debugging session), or perform it directly.
|
||||
ioctl_pdb_code_t code = ioctl_pdb_code_t(internal_ioctl(fn, buf, size, outbuf, outsz));
|
||||
// ioctl_pdb_code_t code = ioctl_pdb_code_t(internal_ioctl dbg->send_ioctl(fn, buf, size, outbuf, outsz));
|
||||
deb(IDA_DEBUG_DEBUGGER, "PDB: send_ioctl(fn=%d) complete. Code=%d\n", fn, int(code));
|
||||
return code;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
HRESULT remote_pdb_access_t::_do_iterate_symbols_ids(
|
||||
const DWORD *ids,
|
||||
size_t count,
|
||||
enum SymTagEnum type,
|
||||
children_visitor_t &visitor)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
for ( size_t i = 0, n = count; i < n; ++i, ++ids )
|
||||
{
|
||||
DWORD tag;
|
||||
pdb_sym_t *cur = create_sym(*ids);
|
||||
pdb_sym_janitor_t janitor_cur(cur);
|
||||
if ( type == SymTagNull
|
||||
|| cur->get_symTag(&tag) == S_OK && tag == type )
|
||||
{
|
||||
hr = visitor.visit_child(*cur);
|
||||
if ( FAILED(hr) )
|
||||
break;
|
||||
}
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
HRESULT remote_pdb_access_t::do_iterate_children(
|
||||
pdb_sym_t &sym,
|
||||
enum SymTagEnum type,
|
||||
children_visitor_t &visitor)
|
||||
{
|
||||
sym_data_t *symbol;
|
||||
ioctl_pdb_code_t code = get_sym_data(sym, &symbol);
|
||||
QASSERT(30205, code == pdb_ok);
|
||||
QASSERT(30206, type < SymTagMax);
|
||||
sym_data_t::children_t &children = symbol->children_infos[type];
|
||||
if ( children.ids == NULL )
|
||||
{
|
||||
qvector<DWORD> children_ids;
|
||||
code = fetch_children_infos(sym, type, &children_ids);
|
||||
if ( code == pdb_ok )
|
||||
{
|
||||
children.cnt = children_ids.size();
|
||||
children.ids = children_ids.extract();
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT hr = E_FAIL;
|
||||
if ( code == pdb_ok )
|
||||
hr = _do_iterate_symbols_ids(
|
||||
children.ids,
|
||||
children.cnt,
|
||||
type,
|
||||
visitor);
|
||||
return hr;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
HRESULT remote_pdb_access_t::load(pdb_sym_t &pdbsym, DWORD id)
|
||||
{
|
||||
sym_data_t *sd;
|
||||
if ( get_sym_data(id, &sd) != pdb_ok )
|
||||
return E_FAIL;
|
||||
QASSERT(30544, pdbsym.whoami() == REMOTE_PDB_SYM);
|
||||
remote_pdb_sym_t &sym = (remote_pdb_sym_t &)pdbsym;
|
||||
sym.set_symbol_data(sd);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
#define HAS_REMAINING_OR_FAIL(Ptr, End) \
|
||||
do \
|
||||
{ \
|
||||
if ( Ptr >= End ) \
|
||||
return E_FAIL; \
|
||||
} while ( false )
|
||||
|
||||
#define ALL_CONSUMED_OR_FAIL(Ptr, End) \
|
||||
do \
|
||||
{ \
|
||||
if ( Ptr != End ) \
|
||||
return E_FAIL; \
|
||||
} while ( false )
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
HRESULT remote_pdb_access_t::handle_fetch_lnnums(
|
||||
pdb_lnnums_t *out,
|
||||
const bytevec_t &resp) const
|
||||
{
|
||||
const uchar *ptr = resp.begin();
|
||||
const uchar *const end = resp.end();
|
||||
uint32 nlines = unpack_dd(&ptr, end);
|
||||
for ( uint32 i = 0; i < nlines; ++i )
|
||||
{
|
||||
HAS_REMAINING_OR_FAIL(ptr, end);
|
||||
pdb_lnnum_t &ln = out->push_back();
|
||||
ln.va = ULONGLONG(unpack_ea64(&ptr, end));
|
||||
ln.length = unpack_dd(&ptr, end);
|
||||
ln.columnNumber = unpack_dd(&ptr, end);
|
||||
ln.columnNumberEnd = unpack_dd(&ptr, end);
|
||||
ln.lineNumber = unpack_dd(&ptr, end);
|
||||
ln.lineNumberEnd = unpack_dd(&ptr, end);
|
||||
ln.file_id = unpack_dd(&ptr, end);
|
||||
ln.statement = unpack_db(&ptr, end);
|
||||
}
|
||||
ALL_CONSUMED_OR_FAIL(ptr, end);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
HRESULT remote_pdb_access_t::sip_retrieve_lines_by_va(
|
||||
pdb_lnnums_t *out,
|
||||
ULONGLONG va,
|
||||
ULONGLONG length)
|
||||
{
|
||||
bytevec_t req, resp;
|
||||
req.pack_ea64(va);
|
||||
req.pack_dq(length);
|
||||
ioctl_pdb_code_t code = perform_op(
|
||||
WIN32_IOCTL_PDB_SIP_FETCH_LINES_BY_VA, req, &resp);
|
||||
return code == pdb_ok ? handle_fetch_lnnums(out, resp) : E_FAIL;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
HRESULT remote_pdb_access_t::sip_retrieve_lines_by_coords(
|
||||
pdb_lnnums_t *out,
|
||||
DWORD file_id,
|
||||
int lnnum,
|
||||
int colnum)
|
||||
{
|
||||
bytevec_t req, resp;
|
||||
req.pack_dd(file_id);
|
||||
req.pack_dd(lnnum);
|
||||
req.pack_dd(colnum);
|
||||
ioctl_pdb_code_t code = perform_op(
|
||||
WIN32_IOCTL_PDB_SIP_FETCH_LINES_BY_COORDS, req, &resp);
|
||||
return code == pdb_ok ? handle_fetch_lnnums(out, resp) : E_FAIL;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
HRESULT remote_pdb_access_t::sip_iterate_symbols_at_ea(
|
||||
ULONGLONG va,
|
||||
ULONGLONG size,
|
||||
enum SymTagEnum tag,
|
||||
children_visitor_t &visitor)
|
||||
{
|
||||
qvector<DWORD> ids;
|
||||
bytevec_t req;
|
||||
req.pack_ea64(va);
|
||||
req.pack_dq(size);
|
||||
req.pack_dd(tag);
|
||||
ioctl_pdb_code_t code = perform_op(
|
||||
WIN32_IOCTL_PDB_SIP_FETCH_SYMBOLS_AT_VA, req, &ids);
|
||||
if ( code != pdb_ok )
|
||||
return E_FAIL;
|
||||
return _do_iterate_symbols_ids(
|
||||
ids.begin(),
|
||||
ids.size(),
|
||||
tag,
|
||||
visitor);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
HRESULT remote_pdb_access_t::sip_iterate_file_compilands(
|
||||
DWORD file_id,
|
||||
children_visitor_t &visitor)
|
||||
{
|
||||
qvector<DWORD> ids;
|
||||
bytevec_t req;
|
||||
req.pack_dd(file_id);
|
||||
ioctl_pdb_code_t code = perform_op(
|
||||
WIN32_IOCTL_PDB_SIP_FETCH_FILE_COMPILANDS, req, &ids);
|
||||
if ( code != pdb_ok )
|
||||
return E_FAIL;
|
||||
return _do_iterate_symbols_ids(
|
||||
ids.begin(),
|
||||
ids.size(),
|
||||
SymTagNull,
|
||||
visitor);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
HRESULT remote_pdb_access_t::sip_retrieve_file_path(
|
||||
qstring *out,
|
||||
qstring *,
|
||||
DWORD file_id)
|
||||
{
|
||||
bytevec_t req, resp;
|
||||
req.pack_dd(file_id);
|
||||
ioctl_pdb_code_t code = perform_op(
|
||||
WIN32_IOCTL_PDB_SIP_FETCH_FILE_PATH, req, &resp);
|
||||
if ( code != pdb_ok )
|
||||
return E_FAIL;
|
||||
|
||||
const uchar *ptr = resp.begin();
|
||||
const uchar *const end = resp.end();
|
||||
HAS_REMAINING_OR_FAIL(ptr, end);
|
||||
*out = unpack_str(&ptr, end);
|
||||
ALL_CONSUMED_OR_FAIL(ptr, end);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
HRESULT remote_pdb_access_t::handle_fetch_file_ids(
|
||||
qvector<DWORD> *out,
|
||||
const bytevec_t &resp) const
|
||||
{
|
||||
const uchar *ptr = resp.begin();
|
||||
const uchar *const end = resp.end();
|
||||
uint32 nfiles = unpack_dd(&ptr, end);
|
||||
out->resize(nfiles);
|
||||
for ( uint32 i = 0; i < nfiles; ++i )
|
||||
{
|
||||
HAS_REMAINING_OR_FAIL(ptr, end);
|
||||
out->at(i) = unpack_dd(&ptr, end);
|
||||
}
|
||||
ALL_CONSUMED_OR_FAIL(ptr, end);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
HRESULT remote_pdb_access_t::sip_retrieve_symbol_files(
|
||||
qvector<DWORD> *out,
|
||||
pdb_sym_t &pdbsym)
|
||||
{
|
||||
QASSERT(30538, pdbsym.whoami() == REMOTE_PDB_SYM);
|
||||
remote_pdb_sym_t &sym = (remote_pdb_sym_t &)pdbsym;
|
||||
bytevec_t req, resp;
|
||||
req.pack_dd(sym.data->get_id());
|
||||
ioctl_pdb_code_t code = perform_op(
|
||||
WIN32_IOCTL_PDB_SIP_FETCH_SYMBOL_FILES, req, &resp);
|
||||
return code == pdb_ok ? handle_fetch_file_ids(out, resp) : E_FAIL;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
HRESULT remote_pdb_access_t::sip_find_files(
|
||||
qvector<DWORD> *out,
|
||||
const char *fileName)
|
||||
{
|
||||
bytevec_t req, resp;
|
||||
req.pack_str(fileName);
|
||||
ioctl_pdb_code_t code = perform_op(
|
||||
WIN32_IOCTL_PDB_SIP_FIND_FILES, req, &resp);
|
||||
return code == pdb_ok ? handle_fetch_file_ids(out, resp) : E_FAIL;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
DWORD remote_pdb_access_t::build_and_register_sym_data(
|
||||
const uchar **raw,
|
||||
const uchar *end)
|
||||
{
|
||||
DWORD child_sym = unpack_dd(raw, end);
|
||||
token_mask_t tokens = unpack_dq(raw, end);
|
||||
uint32 datasz = unpack_dd(raw, end);
|
||||
const uchar *data = (const uchar *)unpack_obj_inplace(raw, end, datasz);
|
||||
cache[child_sym] = new sym_data_t(tokens, data, datasz, SYMDAT_PACKED, &warned);
|
||||
return child_sym;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void remote_pdb_access_t::handle_fetch_response(
|
||||
const uchar **ptr,
|
||||
const uchar *end,
|
||||
qvector<DWORD> *ids_storage)
|
||||
{
|
||||
// Build cache!
|
||||
uint32 nchildren = 0;
|
||||
unpack_obj(&nchildren, sizeof(nchildren), ptr, end);
|
||||
if ( ids_storage != NULL )
|
||||
ids_storage->reserve(nchildren);
|
||||
for ( uint32 i = 0; i < nchildren; i++ )
|
||||
{
|
||||
DWORD created = build_and_register_sym_data(ptr, end);
|
||||
if ( ids_storage != NULL )
|
||||
ids_storage->push_back(created);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
ioctl_pdb_code_t remote_pdb_access_t::perform_op(
|
||||
int op_type,
|
||||
const bytevec_t &oper,
|
||||
void *data)
|
||||
{
|
||||
void *outbuf = NULL;
|
||||
ssize_t outsize = 0;
|
||||
bytevec_t raw;
|
||||
QASSERT(30494, remote_session_id > 0);
|
||||
raw.pack_dd(remote_session_id);
|
||||
if ( !oper.empty() )
|
||||
raw.append(oper.begin(), oper.size());
|
||||
ioctl_pdb_code_t rc = send_ioctl(op_type, raw.begin(), raw.size(), &outbuf, &outsize);
|
||||
if ( rc != pdb_ok )
|
||||
REPORT_ERROR(
|
||||
"PDB symbol extraction is not supported by the remote server",
|
||||
rc);
|
||||
|
||||
// msg(" ok\n");
|
||||
|
||||
// By now, the operation will be done. Let's parse
|
||||
// the contents of the output buffer.
|
||||
const uchar *ptr = (const uchar *)outbuf;
|
||||
const uchar *const end = ptr + outsize;
|
||||
switch ( op_type )
|
||||
{
|
||||
case WIN32_IOCTL_PDB_FETCH_SYMBOL:
|
||||
case WIN32_IOCTL_PDB_FETCH_CHILDREN:
|
||||
case WIN32_IOCTL_PDB_SIP_FETCH_SYMBOLS_AT_VA:
|
||||
case WIN32_IOCTL_PDB_SIP_FETCH_FILE_COMPILANDS:
|
||||
QASSERT(30207, outsize >= (4 /*(unpacked) nchildren*/));
|
||||
handle_fetch_response(&ptr, end, (qvector<DWORD> *)data);
|
||||
break;
|
||||
case WIN32_IOCTL_PDB_SIP_FETCH_LINES_BY_VA:
|
||||
case WIN32_IOCTL_PDB_SIP_FETCH_LINES_BY_COORDS:
|
||||
case WIN32_IOCTL_PDB_SIP_FETCH_FILE_PATH:
|
||||
case WIN32_IOCTL_PDB_SIP_FETCH_SYMBOL_FILES:
|
||||
case WIN32_IOCTL_PDB_SIP_FIND_FILES:
|
||||
{
|
||||
bytevec_t *bvout = (bytevec_t *) data;
|
||||
bvout->append(outbuf, outsize);
|
||||
}
|
||||
break;
|
||||
case WIN32_IOCTL_PDB_CLOSE:
|
||||
break;
|
||||
default:
|
||||
INTERR(30208);
|
||||
}
|
||||
|
||||
qfree(outbuf);
|
||||
|
||||
return pdb_ok;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
ioctl_pdb_code_t remote_pdb_access_t::fetch_children_infos(
|
||||
pdb_sym_t &pdbsym,
|
||||
enum SymTagEnum type,
|
||||
qvector<DWORD> *children_ids)
|
||||
{
|
||||
QASSERT(30539, pdbsym.whoami() == REMOTE_PDB_SYM);
|
||||
remote_pdb_sym_t &sym = (remote_pdb_sym_t &)pdbsym;
|
||||
bytevec_t oper;
|
||||
oper.pack_dd(sym.data->get_id());
|
||||
oper.pack_dd(type);
|
||||
// msg("Fetching children: 0x%x", sym);
|
||||
return perform_op(WIN32_IOCTL_PDB_FETCH_CHILDREN, oper, children_ids);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
sym_data_t *remote_pdb_access_t::get_sym_data_from_cache(DWORD id)
|
||||
{
|
||||
typedef std::map<DWORD,sym_data_t*>::const_iterator citer;
|
||||
citer it = cache.find(id);
|
||||
if ( it != cache.end() )
|
||||
return it->second;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
ioctl_pdb_code_t remote_pdb_access_t::get_sym_data(pdb_sym_t &pdbsym, sym_data_t **out)
|
||||
{
|
||||
QASSERT(30540, pdbsym.whoami() == REMOTE_PDB_SYM);
|
||||
remote_pdb_sym_t &sym = (remote_pdb_sym_t &)pdbsym;
|
||||
DWORD id = sym.data->get_id();
|
||||
return get_sym_data(id, out);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
ioctl_pdb_code_t remote_pdb_access_t::get_sym_data(DWORD id, sym_data_t **out)
|
||||
{
|
||||
sym_data_t *found = get_sym_data_from_cache(id);
|
||||
if ( found != NULL )
|
||||
{
|
||||
*out = found;
|
||||
return pdb_ok;
|
||||
}
|
||||
else
|
||||
{
|
||||
bytevec_t oper;
|
||||
oper.pack_dd(id);
|
||||
ioctl_pdb_code_t rc = perform_op(WIN32_IOCTL_PDB_FETCH_SYMBOL, oper, NULL);
|
||||
if ( rc == pdb_ok )
|
||||
{
|
||||
rc = get_sym_data(id, out);
|
||||
QASSERT(30209, rc == pdb_ok);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
163
idasdk76/plugins/pdb/pdbremote.hpp
Normal file
163
idasdk76/plugins/pdb/pdbremote.hpp
Normal file
@@ -0,0 +1,163 @@
|
||||
|
||||
#ifndef PDBREMOTE_HPP
|
||||
#define PDBREMOTE_HPP
|
||||
|
||||
#include <network.hpp>
|
||||
#include "../../dbg/win32/win32_rpc.h"
|
||||
#include "pdbaccess.hpp"
|
||||
|
||||
// The PDB related code that works on Unix
|
||||
// It connects to a Windows computer and asks to retrieve PDB info
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool is_win32_remote_debugger_loaded();
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
//-V:remote_pdb_access_t:730 not all members of a class are initialized inside the constructor
|
||||
class remote_pdb_access_t : public pdb_access_t
|
||||
{
|
||||
public:
|
||||
remote_pdb_access_t(
|
||||
const pdbargs_t &args,
|
||||
const char *_host,
|
||||
int _port,
|
||||
const char *_pwd)
|
||||
: pdb_access_t(args),
|
||||
host(_host),
|
||||
port(_port),
|
||||
pwd(_pwd),
|
||||
remote_session_id(-1)
|
||||
{
|
||||
set_base_address(args.loaded_base);
|
||||
}
|
||||
|
||||
virtual ~remote_pdb_access_t();
|
||||
|
||||
// Open connection, create PDB session.
|
||||
HRESULT open_connection();
|
||||
// Close PDB session, close connection.
|
||||
void close_connection();
|
||||
|
||||
virtual HRESULT do_iterate_children(
|
||||
pdb_sym_t &sym,
|
||||
enum SymTagEnum type,
|
||||
children_visitor_t &visitor) override;
|
||||
virtual HRESULT load(pdb_sym_t &sym, DWORD id) override;
|
||||
|
||||
virtual HRESULT sip_retrieve_lines_by_va(
|
||||
pdb_lnnums_t *out,
|
||||
ULONGLONG va,
|
||||
ULONGLONG length) override;
|
||||
virtual HRESULT sip_retrieve_lines_by_coords(
|
||||
pdb_lnnums_t *out,
|
||||
DWORD file_id,
|
||||
int lnnum,
|
||||
int colnum) override;
|
||||
virtual HRESULT sip_iterate_symbols_at_ea(
|
||||
ULONGLONG va,
|
||||
ULONGLONG size,
|
||||
enum SymTagEnum tag,
|
||||
children_visitor_t &visitor) override;
|
||||
virtual HRESULT sip_iterate_file_compilands(
|
||||
DWORD file_id,
|
||||
children_visitor_t &visitor) override;
|
||||
virtual HRESULT sip_retrieve_file_path(
|
||||
qstring *out,
|
||||
qstring *errbuf,
|
||||
DWORD file_id) override;
|
||||
virtual HRESULT sip_retrieve_symbol_files(
|
||||
qvector<DWORD> *out,
|
||||
pdb_sym_t &sym) override;
|
||||
virtual HRESULT sip_find_files(
|
||||
qvector<DWORD> *out,
|
||||
const char *name) override;
|
||||
|
||||
virtual pdb_sym_t *create_sym(void *data, bool) override
|
||||
{
|
||||
sym_data_t *sym = (sym_data_t *)data;
|
||||
return new remote_pdb_sym_t(this, sym);
|
||||
}
|
||||
pdb_sym_t *create_sym(DWORD sym_id) { return pdb_access_t::create_sym(sym_id); }
|
||||
|
||||
// Possibly remote operation.
|
||||
// If NULL is returned, it means the symbol is not available, nor
|
||||
// could it be fetched remotely.
|
||||
ioctl_pdb_code_t get_sym_data(pdb_sym_t &sym, sym_data_t **);
|
||||
ioctl_pdb_code_t get_sym_data(DWORD sym_id, sym_data_t **);
|
||||
|
||||
|
||||
private:
|
||||
HRESULT _do_iterate_symbols_ids(
|
||||
const DWORD *ids,
|
||||
size_t count,
|
||||
enum SymTagEnum type,
|
||||
children_visitor_t &visitor);
|
||||
|
||||
#define SAFE_GET(type) \
|
||||
sym_data_t *sym_data; \
|
||||
ioctl_pdb_code_t result = get_sym_data(sym, &sym_data); \
|
||||
if ( result == pdb_ok ) \
|
||||
return sym_data->get_##type(token, out); \
|
||||
else \
|
||||
return E_FAIL
|
||||
|
||||
// Build sym_data_t instance, and register it into the 'cache'.
|
||||
DWORD build_and_register_sym_data(const uchar **raw, const uchar *end);
|
||||
|
||||
// Whenever fetch_children_infos() or get_sym_data() performs
|
||||
// a remote operation, this is used to handle the response
|
||||
// and add the fetched symbol data to the cache.
|
||||
void handle_fetch_response(
|
||||
const uchar **ptr,
|
||||
const uchar *end,
|
||||
qvector<DWORD> *ids_storage);
|
||||
|
||||
// Remote operation.
|
||||
ioctl_pdb_code_t fetch_children_infos(
|
||||
pdb_sym_t &sym,
|
||||
enum SymTagEnum type,
|
||||
qvector<DWORD> *children_ids);
|
||||
|
||||
HRESULT handle_fetch_lnnums(
|
||||
pdb_lnnums_t *out,
|
||||
const bytevec_t &resp) const;
|
||||
|
||||
HRESULT handle_fetch_file_ids(
|
||||
qvector<DWORD> *out,
|
||||
const bytevec_t &resp) const;
|
||||
|
||||
sym_data_t *get_sym_data_from_cache(DWORD id);
|
||||
|
||||
// Low-level interface used by open_connection(), fetch_children_infos(), and get_sym_data().
|
||||
// 'fetch_type' is one of
|
||||
// WIN32_IOCTL_PDB_OPEN,
|
||||
// WIN32_IOCTL_PDB_FETCH_SYMBOL,
|
||||
// WIN32_IOCTL_PDB_FETCH_CHILDREN
|
||||
ioctl_pdb_code_t perform_op(int op_type, const bytevec_t &oper, void *data);
|
||||
|
||||
ioctl_pdb_code_t send_ioctl(
|
||||
int fn,
|
||||
const void *buf,
|
||||
size_t size,
|
||||
void **poutbuf,
|
||||
ssize_t *poutsize);
|
||||
|
||||
std::map<DWORD, sym_data_t*> cache;
|
||||
const char *user_spath;
|
||||
char errbuf[MAXSTR];
|
||||
|
||||
// For the moment, we'll channel all IOCTL requests
|
||||
// through the debugger. Ideally, we should be able to just
|
||||
// use a RPC client.
|
||||
bool load_win32_debugger(void);
|
||||
|
||||
const char *host;
|
||||
int port;
|
||||
const char *pwd;
|
||||
bool was_connected;
|
||||
bool is_dbg_module;
|
||||
int remote_session_id;
|
||||
bool warned = false;
|
||||
};
|
||||
|
||||
#endif // PDBREMOTE_HPP
|
||||
1294
idasdk76/plugins/pdb/sip.cpp
Normal file
1294
idasdk76/plugins/pdb/sip.cpp
Normal file
File diff suppressed because it is too large
Load Diff
9
idasdk76/plugins/pdb/sip.hpp
Normal file
9
idasdk76/plugins/pdb/sip.hpp
Normal file
@@ -0,0 +1,9 @@
|
||||
|
||||
#ifndef PDB_SIP_H
|
||||
#define PDB_SIP_H
|
||||
|
||||
bool apply_debug_info(pdbargs_t &pdbargs);
|
||||
|
||||
#include "pdbaccess.hpp"
|
||||
|
||||
#endif // PDB_SIP_H
|
||||
2424
idasdk76/plugins/pdb/tilbuild.cpp
Normal file
2424
idasdk76/plugins/pdb/tilbuild.cpp
Normal file
File diff suppressed because it is too large
Load Diff
216
idasdk76/plugins/pdb/tilbuild.hpp
Normal file
216
idasdk76/plugins/pdb/tilbuild.hpp
Normal file
@@ -0,0 +1,216 @@
|
||||
#pragma once
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
enum cvt_code_t
|
||||
{
|
||||
cvt_failed,
|
||||
cvt_ok,
|
||||
cvt_typedef // conversion resulted in a typedef to a named type
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// PBD provides the offset of a bitfield inside a bitfield group.
|
||||
// We subclass udt_member_t in order to keep that information separate from
|
||||
// the 'offset' field.
|
||||
struct pdb_udt_member_t : public udt_member_t
|
||||
{
|
||||
uint32 bit_offset; ///< member offset in bits from start of bitfield group
|
||||
};
|
||||
DECLARE_TYPE_AS_MOVABLE(pdb_udt_member_t);
|
||||
typedef qvector<pdb_udt_member_t> pdbudtmembervec_t; ///< vector of pdb udt member objects
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// stripped-down version of udt_type_data_t with only the fields used by pdb.
|
||||
struct pdb_udt_type_data_t : public pdbudtmembervec_t
|
||||
{
|
||||
size_t total_size; ///< total structure size in bytes
|
||||
uint32 taudt_bits; ///< TA... and TAUDT... bits
|
||||
bool is_union; ///< is union or struct?
|
||||
|
||||
pdb_udt_type_data_t(void)
|
||||
: total_size(0),
|
||||
taudt_bits(0),
|
||||
is_union(false)
|
||||
{
|
||||
}
|
||||
|
||||
void convert_to_tinfo_udt(udt_type_data_t *out);
|
||||
};
|
||||
DECLARE_TYPE_AS_MOVABLE(pdb_udt_type_data_t);
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
class til_builder_t
|
||||
{
|
||||
protected:
|
||||
pdb_ctx_t &pv;
|
||||
public:
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
struct tpinfo_t
|
||||
{
|
||||
cvt_code_t cvt_code;
|
||||
bool is_notype;
|
||||
tinfo_t type;
|
||||
til_t *ti; // FIXME: do we need this?
|
||||
tpinfo_t(void) : cvt_code(cvt_ok), is_notype(false), ti(NULL) {}
|
||||
tpinfo_t(til_t *_ti, const tinfo_t &t) : cvt_code(cvt_ok), is_notype(false), type(t), ti(_ti) {}
|
||||
const char *dstr(void) const
|
||||
{
|
||||
if ( cvt_code == cvt_failed )
|
||||
return "#cvt_failed";
|
||||
|
||||
static qstring res;
|
||||
if ( !type.print(&res) )
|
||||
res = "#print_failed";
|
||||
return res.c_str();
|
||||
}
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
til_builder_t(pdb_ctx_t &_pv, til_t *_ti, pdb_access_t *_pa)
|
||||
: pv(_pv),
|
||||
unnamed_idx(0),
|
||||
level(0),
|
||||
ti(_ti),
|
||||
pdb_access(NULL),
|
||||
enregistered_bug(false)
|
||||
{
|
||||
set_pdb_access(_pa);
|
||||
}
|
||||
|
||||
virtual ~til_builder_t()
|
||||
{
|
||||
typemap.clear();
|
||||
tpdefs.clear();
|
||||
handled.clear();
|
||||
creating.clear();
|
||||
unnamed_types.clear();
|
||||
}
|
||||
|
||||
void set_pdb_access(pdb_access_t *_pdb_access)
|
||||
{
|
||||
pdb_access = _pdb_access;
|
||||
}
|
||||
|
||||
typedef std::map<DWORD, tpinfo_t> typemap_t;
|
||||
typedef std::map<DWORD, tinfo_t> tpdefs_t;
|
||||
typedef std::set<DWORD> idset_t;
|
||||
typedef std::map<qstring, int> creating_t;
|
||||
typedef std::set<uint32> unnamed_t;
|
||||
|
||||
struct vft_info_t
|
||||
{
|
||||
udt_type_data_t udt; // collected vft members
|
||||
qstring base0; // base vftable at offset 0
|
||||
|
||||
vft_info_t() { udt.taudt_bits |= TAUDT_VFTABLE; }
|
||||
bool empty() const { return udt.empty() && base0.empty(); }
|
||||
};
|
||||
typedef std::map<qstring, vft_info_t> vftmap_t;
|
||||
|
||||
// remove `anonymous-namespace'::
|
||||
// also remove `anonymous namespace'::
|
||||
void remove_anonymous_namespaces(qstring &storage);
|
||||
|
||||
bool get_symbol_type(tpinfo_t *out, pdb_sym_t &sym, int *p_id);
|
||||
bool retrieve_type(tpinfo_t *out, pdb_sym_t &sym, pdb_sym_t *parent, int *p_id);
|
||||
bool retrieve_arguments(
|
||||
pdb_sym_t &sym,
|
||||
func_type_data_t &fi,
|
||||
pdb_sym_t *funcSym);
|
||||
cm_t convert_cc(DWORD cc0) const;
|
||||
bool get_variant_string_value(qstring *out, pdb_sym_t &sym) const;
|
||||
uint32 get_variant_long_value(pdb_sym_t &sym) const;
|
||||
bool begin_creation(DWORD tag, const qstring &name, uint32 *p_id);
|
||||
uint32 end_creation(const qstring &name);
|
||||
bool is_member_func(tinfo_t *class_type, pdb_sym_t &typeSym, pdb_sym_t *funcSym);
|
||||
bool is_frame_reg(int regnum) const;
|
||||
bool is_complex_return(pdb_sym_t &sym) const;
|
||||
bool is_unnamed_tag_typedef(const tinfo_t &tif) const;
|
||||
bool is_intel386(DWORD machine_type) const;
|
||||
bool is_arm(DWORD machine_type) const;
|
||||
int get_symbol_funcarg_info(
|
||||
funcarg_t *out,
|
||||
pdb_sym_t &sym,
|
||||
DWORD /*dwDataKind*/,
|
||||
DWORD locType,
|
||||
int stack_off);
|
||||
void enum_function_args(pdb_sym_t &sym, func_type_data_t &args);
|
||||
cvt_code_t verify_struct(pdb_udt_type_data_t &udt) const;
|
||||
cvt_code_t verify_union(
|
||||
pdb_udt_type_data_t *out,
|
||||
pdb_udt_type_data_t::iterator p1,
|
||||
pdb_udt_type_data_t::const_iterator p2) const;
|
||||
cvt_code_t create_union(
|
||||
tinfo_t *out,
|
||||
size_t *p_total_size,
|
||||
pdb_udt_type_data_t::iterator p1,
|
||||
pdb_udt_type_data_t::const_iterator p2) const;
|
||||
cvt_code_t convert_basetype(tpinfo_t *out, DWORD baseType, int size) const;
|
||||
cvt_code_t make_vtable_struct(tinfo_t *out, pdb_sym_t &sym);
|
||||
cvt_code_t convert_udt(tinfo_t *out, pdb_sym_t &sym, DWORD64 size);
|
||||
cvt_code_t create_udt(tinfo_t *out, pdb_udt_type_data_t *udt, int udtKind, const char *udt_name) const;
|
||||
cvt_code_t create_udt_ref(tinfo_t *out, pdb_udt_type_data_t *udt, int udt_kind) const;
|
||||
cvt_code_t really_convert_type(tpinfo_t *out, pdb_sym_t &sym, pdb_sym_t *parent, DWORD tag);
|
||||
cvt_code_t convert_type(
|
||||
tpinfo_t *out,
|
||||
pdb_sym_t &sym,
|
||||
pdb_sym_t *parent,
|
||||
DWORD type,
|
||||
DWORD tag);
|
||||
cvt_code_t handle_overlapping_members(pdb_udt_type_data_t *udt) const;
|
||||
// Will iterate on children, and call handle_function_child()
|
||||
HRESULT handle_symbols(pdb_sym_t &pGlobal);
|
||||
HRESULT handle_globals(pdb_sym_t &pGlobal);
|
||||
HRESULT handle_publics(pdb_sym_t &pGlobal);
|
||||
HRESULT handle_types(pdb_sym_t &pGlobal);
|
||||
HRESULT build(pdb_sym_t &pGlobal);
|
||||
ea_t get_load_address() const { return pdb_access->get_base_address(); }
|
||||
HRESULT handle_symbol(pdb_sym_t &sym);
|
||||
size_t get_symbol_type_length(pdb_sym_t &sym) const;
|
||||
void create_vftables();
|
||||
// check for MS or IDA vftable name,
|
||||
// get type ordinal of vftable
|
||||
// returns the type is creating
|
||||
bool get_vft_name(qstring *vft_name, uint32 *ord, const char *udt_name, uint32_t offset=0);
|
||||
|
||||
virtual HRESULT before_iterating(pdb_sym_t &global_sym);
|
||||
virtual HRESULT after_iterating(pdb_sym_t &global_sym);
|
||||
virtual bool iterate_symbols_once_more(pdb_sym_t & /*global_sym*/) { return false; }
|
||||
virtual bool get_symbol_name(pdb_sym_t &sym, qstring &storage);
|
||||
virtual bool handle_symbol_at_ea(
|
||||
pdb_sym_t &sym,
|
||||
DWORD tag,
|
||||
ea_t ea,
|
||||
qstring &name);
|
||||
virtual void type_created(ea_t /*ea*/, int /*id*/, const char * /*name*/, const tinfo_t & /*ptr*/) const;
|
||||
virtual void handle_function_type(pdb_sym_t &fun_sym, ea_t ea);
|
||||
virtual HRESULT handle_function_child(
|
||||
pdb_sym_t &fun_sym,
|
||||
ea_t ea,
|
||||
pdb_sym_t &child_sym,
|
||||
DWORD child_tag,
|
||||
DWORD child_loc_type);
|
||||
virtual cvt_code_t handle_unnamed_overlapping_member(
|
||||
pdb_udt_type_data_t * /*udt*/,
|
||||
qstack<qstring> * /*union_names*/,
|
||||
qstring * /*name*/) const
|
||||
{
|
||||
return cvt_ok;
|
||||
}
|
||||
|
||||
protected:
|
||||
typemap_t typemap; // id -> type info
|
||||
tpdefs_t tpdefs; // id -> enum type defined in base til
|
||||
idset_t handled; // set of handled symbols
|
||||
creating_t creating;
|
||||
unnamed_t unnamed_types;
|
||||
vftmap_t vftmap; // vftable name -> vft info
|
||||
int unnamed_idx;
|
||||
int level;
|
||||
|
||||
public:
|
||||
til_t *ti;
|
||||
pdb_access_t *pdb_access;
|
||||
bool enregistered_bug;
|
||||
};
|
||||
198
idasdk76/plugins/pdb/varser.hpp
Normal file
198
idasdk76/plugins/pdb/varser.hpp
Normal file
@@ -0,0 +1,198 @@
|
||||
|
||||
#ifndef VARSER_HPP
|
||||
#define VARSER_HPP
|
||||
|
||||
// Variant serializer/deserializer.
|
||||
struct varser_t
|
||||
{
|
||||
#ifdef __NT__
|
||||
static bool serialize(bytevec_t &out, const VARIANT &var);
|
||||
#else
|
||||
static bool deserialize(VARIANT &var, const uchar **in, const uchar *const end);
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef __NT__
|
||||
//-------------------------------------------------------------------------
|
||||
bool varser_t::serialize(bytevec_t &out, const VARIANT &var)
|
||||
{
|
||||
out.pack_dw(var.vt);
|
||||
if ( (var.vt & VT_BYREF) == VT_BYREF
|
||||
|| (var.vt & VT_ARRAY) == VT_ARRAY )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const size_t sz_before = out.size();
|
||||
switch ( var.vt )
|
||||
{
|
||||
case VT_EMPTY: // = 0x0000,
|
||||
case VT_NULL: // = 0x0001,
|
||||
break;
|
||||
case VT_I2: // = 0x0002,
|
||||
case VT_UI2: // = 0x0012,
|
||||
out.pack_dw(var.uiVal);
|
||||
break;
|
||||
case VT_I4: // = 0x0003,
|
||||
case VT_UI4: // = 0x0013,
|
||||
out.pack_dd(var.ulVal);
|
||||
break;
|
||||
case VT_R4: // = 0x0004,
|
||||
out.pack_dd(*(uint32*)&var.fltVal);
|
||||
break;
|
||||
case VT_R8: // = 0x0005,
|
||||
out.pack_dq(*(uint64*)&var.dblVal);
|
||||
break;
|
||||
case VT_CY: // = 0x0006,
|
||||
case VT_DATE: // = 0x0007,
|
||||
break;
|
||||
case VT_BSTR: // = 0x0008,
|
||||
{
|
||||
uint8 *ptr = (uint8*) var.bstrVal;
|
||||
ptr -= 4;
|
||||
uint32 bcnt = * (uint32*) ptr;
|
||||
out.pack_buf(ptr + 4, bcnt);
|
||||
}
|
||||
break;
|
||||
case VT_DISPATCH: // = 0x0009,
|
||||
case VT_ERROR: // = 0x000A,
|
||||
case VT_BOOL: // = 0x000B,
|
||||
case VT_VARIANT: // = 0x000C,
|
||||
case VT_UNKNOWN: // = 0x000D,
|
||||
case VT_DECIMAL: // = 0x000E,
|
||||
case VT_I1: // = 0x0010,
|
||||
case VT_UI1: // = 0x0011,
|
||||
out.pack_db(var.bVal);
|
||||
break;
|
||||
case VT_I8: // = 0x0014,
|
||||
case VT_UI8: // = 0x0015,
|
||||
out.pack_dq(var.ullVal);
|
||||
break;
|
||||
case VT_INT: // = 0x0016,
|
||||
case VT_UINT: // = 0x0017,
|
||||
case VT_HRESULT: // = 0x0019,
|
||||
out.pack_dd(var.uintVal);
|
||||
break;
|
||||
case VT_VOID: // = 0x0018,
|
||||
case VT_PTR: // = 0x001A,
|
||||
case VT_SAFEARRAY: // = 0x001B,
|
||||
case VT_CARRAY: // = 0x001C,
|
||||
case VT_USERDEFINED: // = 0x001D,
|
||||
case VT_LPSTR: // = 0x001E,
|
||||
case VT_LPWSTR: // = 0x001F,
|
||||
case VT_RECORD: // = 0x0024,
|
||||
case VT_INT_PTR: // = 0x0025,
|
||||
case VT_UINT_PTR: // = 0x0026,
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
return out.size() > sz_before;
|
||||
}
|
||||
#else
|
||||
//-------------------------------------------------------------------------
|
||||
bool varser_t::deserialize(VARIANT &var, const uchar **in, const uchar *const end)
|
||||
{
|
||||
var.vt = unpack_dw(in, end);
|
||||
if ( (var.vt & VT_BYREF) == VT_BYREF
|
||||
|| (var.vt & VT_ARRAY) == VT_ARRAY )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ok = false;
|
||||
switch ( var.vt )
|
||||
{
|
||||
case VT_EMPTY: // = 0x0000,
|
||||
case VT_NULL: // = 0x0001,
|
||||
break;
|
||||
case VT_I2: // = 0x0002,
|
||||
case VT_UI2: // = 0x0012,
|
||||
var.uiVal = unpack_dw(in, end);
|
||||
ok = true;
|
||||
break;
|
||||
case VT_I4: // = 0x0003,
|
||||
case VT_UI4: // = 0x0013,
|
||||
var.ulVal = unpack_dd(in, end);
|
||||
ok = true;
|
||||
break;
|
||||
case VT_R4: // = 0x0004,
|
||||
{
|
||||
uint32 res = unpack_dd(in, end);
|
||||
var.fltVal = *(FLOAT*)&res;
|
||||
ok = true;
|
||||
}
|
||||
break;
|
||||
case VT_R8: // = 0x0005,
|
||||
{
|
||||
uint64 res = unpack_dq(in, end);
|
||||
var.dblVal = *(DOUBLE*)&res;
|
||||
ok = true;
|
||||
}
|
||||
break;
|
||||
case VT_CY: // = 0x0006,
|
||||
case VT_DATE: // = 0x0007,
|
||||
break;
|
||||
case VT_BSTR: // = 0x0008,
|
||||
{
|
||||
uint32 bcnt = unpack_dd(in, end);
|
||||
uint32 nbytes = bcnt + 4 + 2; // +2 for terminating null character
|
||||
QASSERT(30472, nbytes > bcnt); // check for integer overflow
|
||||
uint8 *raw = (uint8 *)qalloc(nbytes);
|
||||
if ( raw != NULL )
|
||||
{
|
||||
*(uint32*)raw = bcnt;
|
||||
raw += 4;
|
||||
unpack_obj(raw, bcnt, in, end);
|
||||
raw[bcnt] = '\0';
|
||||
raw[bcnt+1] = '\0';
|
||||
var.bstrVal = raw;
|
||||
ok = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case VT_LPSTR: // = 0x001E,
|
||||
case VT_LPWSTR: // = 0x001F,
|
||||
{
|
||||
char *tmp = qstrdup(unpack_str(in, end));
|
||||
var.byref = tmp;
|
||||
ok = true;
|
||||
}
|
||||
break;
|
||||
case VT_DISPATCH: // = 0x0009,
|
||||
case VT_ERROR: // = 0x000A,
|
||||
case VT_BOOL: // = 0x000B,
|
||||
case VT_VARIANT: // = 0x000C,
|
||||
case VT_UNKNOWN: // = 0x000D,
|
||||
case VT_DECIMAL: // = 0x000E,
|
||||
case VT_I1: // = 0x0010,
|
||||
case VT_UI1: // = 0x0011,
|
||||
var.bVal = unpack_db(in, end);
|
||||
ok = true;
|
||||
break;
|
||||
case VT_I8: // = 0x0014,
|
||||
case VT_UI8: // = 0x0015,
|
||||
var.ullVal = unpack_dq(in, end);
|
||||
ok = true;
|
||||
break;
|
||||
case VT_INT: // = 0x0016,
|
||||
case VT_UINT: // = 0x0017,
|
||||
case VT_HRESULT: // = 0x0019,
|
||||
var.uintVal = unpack_dd(in, end);
|
||||
ok = true;
|
||||
break;
|
||||
case VT_VOID: // = 0x0018,
|
||||
case VT_PTR: // = 0x001A,
|
||||
case VT_SAFEARRAY: // = 0x001B,
|
||||
case VT_CARRAY: // = 0x001C,
|
||||
case VT_USERDEFINED: // = 0x001D,
|
||||
case VT_RECORD: // = 0x0024,
|
||||
case VT_INT_PTR: // = 0x0025,
|
||||
case VT_UINT_PTR: // = 0x0026,
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
#endif // __NT__
|
||||
|
||||
#endif // VARSER_HPP
|
||||
21
idasdk76/plugins/plugin.mak
Normal file
21
idasdk76/plugins/plugin.mak
Normal file
@@ -0,0 +1,21 @@
|
||||
|
||||
__FUZZ_PLUGINS__=1
|
||||
|
||||
SRC_PATH = $(IDA)plugins/
|
||||
ifdef EXAMPLE
|
||||
BIN_PATH = $(R)plugins-examples/
|
||||
else
|
||||
BIN_PATH = $(R)plugins/
|
||||
endif
|
||||
|
||||
ifndef NO_DEFAULT_TARGETS
|
||||
BASE_OBJS += $(F)$(PROC)$(O)
|
||||
endif
|
||||
|
||||
include ../../module.mak
|
||||
|
||||
ifdef __NT__
|
||||
ifndef NDEBUG
|
||||
$(MODULES): PDBFLAGS = /PDB:$(@:$(DLLEXT)=.pdb)
|
||||
endif
|
||||
endif
|
||||
12
idasdk76/plugins/procext/makefile
Normal file
12
idasdk76/plugins/procext/makefile
Normal file
@@ -0,0 +1,12 @@
|
||||
PROC=nec
|
||||
|
||||
include ../plugin.mak
|
||||
|
||||
# MAKEDEP dependency list ------------------
|
||||
$(F)nec$(O) : $(I)bitrange.hpp $(I)bytes.hpp $(I)config.hpp \
|
||||
$(I)fpro.h $(I)funcs.hpp $(I)ida.hpp \
|
||||
$(I)idp.hpp $(I)ieee.h $(I)kernwin.hpp $(I)lines.hpp \
|
||||
$(I)llong.hpp $(I)loader.hpp \
|
||||
$(I)nalt.hpp $(I)netnode.hpp $(I)pro.h \
|
||||
$(I)range.hpp $(I)segment.hpp $(I)ua.hpp $(I)xref.hpp \
|
||||
nec.cpp
|
||||
317
idasdk76/plugins/procext/nec.cpp
Normal file
317
idasdk76/plugins/procext/nec.cpp
Normal file
@@ -0,0 +1,317 @@
|
||||
/*
|
||||
* This is a sample plugin module
|
||||
* It extends the IBM PC processor module to disassemble some NEC V20 instructions
|
||||
* This is a sample file, it supports just two instructions!
|
||||
*
|
||||
*/
|
||||
|
||||
#include <ida.hpp>
|
||||
#include <idp.hpp>
|
||||
#include <bytes.hpp>
|
||||
#include <loader.hpp>
|
||||
#include <kernwin.hpp>
|
||||
|
||||
int data_id;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Context data for the plugin. This object is created by the init()
|
||||
// function and hold all local data.
|
||||
struct plugin_ctx_t : public plugmod_t, public event_listener_t
|
||||
{
|
||||
ea_t ea = 0; // current address within the instruction
|
||||
|
||||
netnode nec_node;
|
||||
bool hooked = false;
|
||||
|
||||
plugin_ctx_t();
|
||||
~plugin_ctx_t();
|
||||
|
||||
// This function is called when the user invokes the plugin.
|
||||
virtual bool idaapi run(size_t) override;
|
||||
// This function is called upon some events.
|
||||
virtual ssize_t idaapi on_event(ssize_t code, va_list va) override;
|
||||
|
||||
size_t ana(insn_t &insn);
|
||||
void process_rm(insn_t &insn, op_t &x, uchar postbyte);
|
||||
};
|
||||
|
||||
static const char node_name[] = "$ sample NEC processor extender parameters";
|
||||
|
||||
|
||||
// Some definitions from IBM PC:
|
||||
|
||||
#define segrg specval_shorts.high // IBM PC expects the segment address
|
||||
// to be here
|
||||
#define aux_short 0x0020 // short (byte) displacement used
|
||||
#define aux_basess 0x0200 // SS based instruction
|
||||
|
||||
#define R_ss 18
|
||||
#define R_ds 19
|
||||
//--------------------------------------------------------------------------
|
||||
// This plugin supports just 2 instructions:
|
||||
// Feel free to add more...
|
||||
|
||||
// 0FH 20H ADD4S ; Addition for packed BCD strings
|
||||
// 0FH 12H Postbyte CLEAR1 reg/mem8,CL ; Clear one bit
|
||||
|
||||
enum nec_insn_type_t
|
||||
{
|
||||
NEC_add4s = CUSTOM_INSN_ITYPE,
|
||||
NEC_clear1,
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
static int get_dataseg(insn_t &insn, int defseg)
|
||||
{
|
||||
if ( defseg == R_ss )
|
||||
insn.auxpref |= aux_basess;
|
||||
return defseg;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// process r/m byte of the instruction
|
||||
//
|
||||
void plugin_ctx_t::process_rm(insn_t &insn, op_t &x, uchar postbyte)
|
||||
{
|
||||
int Mod = (postbyte >> 6) & 3;
|
||||
x.reg = postbyte & 7;
|
||||
if ( Mod == 3 ) // register
|
||||
{
|
||||
if ( x.dtype == dt_byte )
|
||||
x.reg += 8;
|
||||
x.type = o_reg;
|
||||
}
|
||||
else // memory
|
||||
{
|
||||
if ( Mod == 0 && x.reg == 6 )
|
||||
{
|
||||
x.type = o_mem;
|
||||
x.offb = uchar(ea-insn.ea);
|
||||
x.addr = get_word(ea); ea+=2;
|
||||
x.segrg = (uint16)get_dataseg(insn, R_ds);
|
||||
}
|
||||
else
|
||||
{
|
||||
x.type = o_phrase; // x.phrase contains the base register
|
||||
x.addr = 0;
|
||||
int reg = (x.phrase == 2 || x.phrase == 3 || x.phrase == 6) ? R_ss : R_ds;
|
||||
x.segrg = (uint16)get_dataseg(insn, reg);
|
||||
// [bp+si],[bp+di],[bp] by SS
|
||||
if ( Mod != 0 )
|
||||
{
|
||||
x.type = o_displ; // i.e. phrase + offset
|
||||
x.offb = uchar(ea-insn.ea);
|
||||
if ( Mod == 1 )
|
||||
{
|
||||
x.addr = char(get_byte(ea++));
|
||||
insn.auxpref |= aux_short;
|
||||
}
|
||||
else
|
||||
{
|
||||
x.addr = get_word(ea); ea+=2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Analyze an instruction and fill the 'insn' structure
|
||||
size_t plugin_ctx_t::ana(insn_t &insn)
|
||||
{
|
||||
int code = get_byte(ea++);
|
||||
if ( code != 0x0F )
|
||||
return 0;
|
||||
code = get_byte(ea++);
|
||||
switch ( code )
|
||||
{
|
||||
case 0x20:
|
||||
insn.itype = NEC_add4s;
|
||||
return 2;
|
||||
case 0x12:
|
||||
insn.itype = NEC_clear1;
|
||||
{
|
||||
uchar postbyte = get_byte(ea++);
|
||||
process_rm(insn, insn.Op1, postbyte);
|
||||
insn.Op2.type = o_reg;
|
||||
insn.Op2.reg = 9; // 9 is CL for IBM PC
|
||||
return size_t(ea - insn.ea);
|
||||
}
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Return the instruction mnemonics
|
||||
const char *get_insn_mnem(const insn_t &insn)
|
||||
{
|
||||
if ( insn.itype == NEC_add4s )
|
||||
return "add4s";
|
||||
return "clear1";
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// This function can be hooked to various kernel events.
|
||||
// In this particular plugin we hook to the HT_IDP group.
|
||||
// As soon the kernel needs to decode and print an instruction, it will
|
||||
// generate some events that we intercept and provide our own response.
|
||||
//
|
||||
// We extend the processor module to disassemble opcode 0x0F
|
||||
// (This is a hypothetical example)
|
||||
// There are 2 different possible approaches for the processor extensions:
|
||||
// A. Quick & dirty
|
||||
// Implement reaction to ev_ana_insn and ev_out_insn.
|
||||
// The first checks if the instruction is valid.
|
||||
// The second generates its text.
|
||||
// B. Thourough and clean
|
||||
// Implement all relevant callbacks.
|
||||
// ev_ana_insn fills the 'insn' structure.
|
||||
// ev_emu_insn creates all xrefs using ua_add_[cd]ref functions.
|
||||
// ev_out_insn generates the textual representation of the instruction.
|
||||
// It is required only if the instruction requires special processing
|
||||
// or the processor module cannot handle the custom instruction for
|
||||
// any reason.
|
||||
// ev_out_operand generates the operand representation (only if the
|
||||
// operand requires special processing).
|
||||
// ev_out_mnem generates the instruction mnemonics.
|
||||
// The main difference between these 2 approaches is in the creation of
|
||||
// cross-references and the amount of special processing required by the
|
||||
// new instructions.
|
||||
|
||||
// The quick & dirty approach.
|
||||
// We just produce the instruction mnemonics along with its operands.
|
||||
// No cross-references are created. No special processing.
|
||||
ssize_t idaapi plugin_ctx_t::on_event(ssize_t code, va_list va)
|
||||
{
|
||||
switch ( code )
|
||||
{
|
||||
case processor_t::ev_ana_insn:
|
||||
{
|
||||
insn_t *insn = va_arg(va, insn_t *);
|
||||
ea = insn->ea;
|
||||
size_t length = ana(*insn);
|
||||
if ( length )
|
||||
{
|
||||
insn->size = (uint16)length;
|
||||
return insn->size; // event processed
|
||||
}
|
||||
}
|
||||
break;
|
||||
case processor_t::ev_out_mnem:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
const insn_t &insn = ctx->insn;
|
||||
if ( insn.itype >= CUSTOM_INSN_ITYPE )
|
||||
{
|
||||
ctx->out_line(get_insn_mnem(insn), COLOR_INSN);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0; // event is not processed
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Initialize the plugin.
|
||||
// IDA will call this function only once.
|
||||
// If this function returns nullptr, IDA will unload the plugin.
|
||||
// Otherwise the plugin returns a pointer to a newly created context structure.
|
||||
//
|
||||
// In this example we check the processor type and make the decision.
|
||||
// You may or may not check any other conditions to decide what you do:
|
||||
// whether your plugin wants to work with the database or not.
|
||||
|
||||
static plugmod_t *idaapi init()
|
||||
{
|
||||
processor_t &ph = PH;
|
||||
if ( ph.id != PLFM_386 )
|
||||
return nullptr;
|
||||
auto plugmod = new plugin_ctx_t;
|
||||
set_module_data(&data_id, plugmod);
|
||||
return plugmod;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
plugin_ctx_t::plugin_ctx_t()
|
||||
{
|
||||
nec_node.create(node_name);
|
||||
hooked = nec_node.altval(0) != 0;
|
||||
if ( hooked )
|
||||
{
|
||||
hook_event_listener(HT_IDP, this);
|
||||
msg("NEC V20 processor extender is enabled\n");
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Terminate the plugin.
|
||||
// This destructor will be called before unloading the plugin.
|
||||
plugin_ctx_t::~plugin_ctx_t()
|
||||
{
|
||||
clr_module_data(data_id);
|
||||
// listeners are uninstalled automatically
|
||||
// when the owner module is unloaded
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// The plugin method
|
||||
// This is the main function of plugin.
|
||||
// It will be called when the user selects the plugin from the menu.
|
||||
// The input argument is usually zero. Non-zero values can be specified
|
||||
// by using load_and_run_plugin() or through plugins.cfg file (discouraged).
|
||||
bool idaapi plugin_ctx_t::run(size_t)
|
||||
{
|
||||
if ( hooked )
|
||||
unhook_event_listener(HT_IDP, this);
|
||||
else
|
||||
hook_event_listener(HT_IDP, this);
|
||||
hooked = !hooked;
|
||||
nec_node.create(node_name);
|
||||
nec_node.altset(0, hooked);
|
||||
info("AUTOHIDE NONE\n"
|
||||
"NEC V20 processor extender now is %s", hooked ? "enabled" : "disabled");
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static const char comment[] = "NEC V20 processor extender";
|
||||
static const char help[] =
|
||||
"A sample plugin module\n"
|
||||
"\n"
|
||||
"This module shows you how to create plugin modules.\n"
|
||||
"\n"
|
||||
"It supports some NEC V20 instructions\n"
|
||||
"and shows the current address.\n";
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// This is the preferred name of the plugin module in the menu system
|
||||
// The preferred name may be overridden in plugins.cfg file
|
||||
|
||||
static const char desired_name[] = "NEC V20 processor extender";
|
||||
|
||||
// This is the preferred hotkey for the plugin module
|
||||
// The preferred hotkey may be overridden in plugins.cfg file
|
||||
|
||||
static const char desired_hotkey[] = "";
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// PLUGIN DESCRIPTION BLOCK
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
plugin_t PLUGIN =
|
||||
{
|
||||
IDP_INTERFACE_VERSION,
|
||||
PLUGIN_PROC // this is a processor extension plugin
|
||||
| PLUGIN_MULTI, // this plugin can work with multiple idbs in parallel
|
||||
init, // initialize
|
||||
nullptr,
|
||||
nullptr,
|
||||
comment, // long comment about the plugin. not used.
|
||||
help, // multiline help about the plugin. not used.
|
||||
desired_name, // the preferred short name of the plugin
|
||||
desired_hotkey // the preferred hotkey to run the plugin
|
||||
};
|
||||
26
idasdk76/plugins/pyplg.mak
Normal file
26
idasdk76/plugins/pyplg.mak
Normal file
@@ -0,0 +1,26 @@
|
||||
|
||||
# definitions for idapython (& other plugins dynamically linked to Python)
|
||||
ifdef __NT__
|
||||
PYTHON_CFLAGS := -I"$(PYTHON_ROOT)/include"
|
||||
ifeq ($(PYTHON_VERSION_MAJOR),3)
|
||||
PYTHON_LDFLAGS := "$(PYTHON_ROOT)/libs/python$(PYTHON_VERSION_MAJOR).lib"
|
||||
else
|
||||
PYTHON_LDFLAGS := "$(PYTHON_ROOT)/libs/python$(PYTHON_VERSION_MAJOR)$(PYTHON_VERSION_MINOR).lib"
|
||||
endif
|
||||
else
|
||||
PYTHON_CFLAGS := $(shell $(PYTHON)-config --includes)
|
||||
ifdef __APPLE_SILICON__
|
||||
# to avoid codesigning complications on arm64 macs, we link against a stub tbd file. see plugins/idapython/tbd.readme
|
||||
PYTHON_LDFLAGS := -L$(R) -lpython$(PYTHON_VERSION_MAJOR) -ldl -framework CoreFoundation
|
||||
else
|
||||
# Yay! https://bugs.python.org/issue36721
|
||||
ifeq ($(PYTHON_VERSION_MAJOR),3)
|
||||
USE_EMBED := $(shell [ $(PYTHON_VERSION_MINOR) -ge 8 ] && echo true)
|
||||
endif
|
||||
ifeq ($(USE_EMBED),true)
|
||||
PYTHON_LDFLAGS := $(shell $(PYTHON)-config --ldflags --embed)
|
||||
else
|
||||
PYTHON_LDFLAGS := $(shell $(PYTHON)-config --ldflags)
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
168
idasdk76/plugins/qproject/edge.cpp
Normal file
168
idasdk76/plugins/qproject/edge.cpp
Normal file
@@ -0,0 +1,168 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
||||
** All rights reserved.
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** This file is part of the examples of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** Commercial Usage
|
||||
** Licensees holding valid Qt Commercial licenses may use this file in
|
||||
** accordance with the Qt Commercial License Agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Nokia.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3.0 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU General Public License version 3.0 requirements will be
|
||||
** met: http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include <QPainter>
|
||||
|
||||
#include "edge.h"
|
||||
#include "node.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
//lint -e1535 member function '' exposes lower access pointer member ''
|
||||
//lint -e1536 member function '' exposes lower access member ''
|
||||
//lint -e1537 const member function '' exposes pointer member '' as pointer to non-const
|
||||
//lint -e1540 non-static pointer data member '' not deallocated nor zeroed by destructor
|
||||
//lint -e2466 '' was used despite being marked as 'unused'
|
||||
|
||||
static const double Pi = 3.14159265358979323846264338327950288419717;
|
||||
static const double TwoPi = 2.0 * Pi;
|
||||
|
||||
Edge::Edge(Node *_sourceNode, Node *_destNode)
|
||||
: arrowSize(10)
|
||||
{
|
||||
setAcceptedMouseButtons(0);
|
||||
source = _sourceNode;
|
||||
dest = _destNode;
|
||||
source->addEdge(this);
|
||||
dest->addEdge(this);
|
||||
adjust();
|
||||
}
|
||||
|
||||
Edge::~Edge()
|
||||
{
|
||||
}
|
||||
|
||||
Node *Edge::sourceNode() const
|
||||
{
|
||||
return source;
|
||||
}
|
||||
|
||||
void Edge::setSourceNode(Node *node)
|
||||
{
|
||||
source = node;
|
||||
adjust();
|
||||
}
|
||||
|
||||
Node *Edge::destNode() const
|
||||
{
|
||||
return dest;
|
||||
}
|
||||
|
||||
void Edge::setDestNode(Node *node)
|
||||
{
|
||||
dest = node;
|
||||
adjust();
|
||||
}
|
||||
|
||||
void Edge::adjust()
|
||||
{
|
||||
if ( !source || !dest )
|
||||
return;
|
||||
|
||||
QRectF srect = source->boundingRect();
|
||||
QRectF drect = dest->boundingRect();
|
||||
|
||||
QLineF line(mapFromItem(source, srect.width() / 2, srect.height() / 2),
|
||||
mapFromItem(dest, drect.width() / 2, drect.height() / 2));
|
||||
qreal length = line.length();
|
||||
|
||||
prepareGeometryChange();
|
||||
|
||||
if ( length > qreal(40.) )
|
||||
{
|
||||
qreal line_angle = line.angle();
|
||||
qreal angle = line_angle > 90. ? fmod(line_angle, 90.0) : line_angle;
|
||||
qreal dist = qMax(angle, 45.0) - qMin(angle, 45.0);
|
||||
dist += 80.0 - dist;
|
||||
QPointF edgeOffset((line.dx() * dist) / length, (line.dy() * dist) / length);
|
||||
sourcePoint = line.p1() + edgeOffset;
|
||||
destPoint = line.p2() - edgeOffset;
|
||||
qreal new_angle = QLineF(sourcePoint, destPoint).angle();
|
||||
if ( qAbs(new_angle - line_angle) > 90. )
|
||||
sourcePoint = destPoint = line.p1();
|
||||
}
|
||||
else
|
||||
{
|
||||
sourcePoint = destPoint = line.p1();
|
||||
}
|
||||
}
|
||||
|
||||
QRectF Edge::boundingRect() const
|
||||
{
|
||||
if ( !source || !dest )
|
||||
return QRectF();
|
||||
|
||||
qreal penWidth = 1;
|
||||
qreal extra = (penWidth + arrowSize) / 2.0;
|
||||
|
||||
QRectF r(sourcePoint, QSizeF(destPoint.x() - sourcePoint.x(),
|
||||
destPoint.y() - sourcePoint.y()));
|
||||
|
||||
return r.normalized().adjusted(-extra, -extra, extra, extra);
|
||||
}
|
||||
|
||||
void Edge::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
|
||||
{
|
||||
if ( !source || !dest )
|
||||
return;
|
||||
|
||||
QLineF line(sourcePoint, destPoint);
|
||||
if ( qFuzzyCompare(line.length(), qreal(0.)) )
|
||||
return;
|
||||
|
||||
// Draw the line itself
|
||||
painter->setPen(QPen(Qt::black, 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
|
||||
painter->drawLine(line);
|
||||
|
||||
// Draw the arrows
|
||||
double angle = ::acos(line.dx() / line.length());
|
||||
if ( line.dy() >= 0 )
|
||||
angle = TwoPi - angle;
|
||||
|
||||
QPointF destArrowP1 = destPoint + QPointF(sin(angle - Pi / 3) * arrowSize,
|
||||
cos(angle - Pi / 3) * arrowSize);
|
||||
QPointF destArrowP2 = destPoint + QPointF(sin(angle - Pi + Pi / 3) * arrowSize,
|
||||
cos(angle - Pi + Pi / 3) * arrowSize);
|
||||
|
||||
painter->setBrush(Qt::black);
|
||||
|
||||
painter->drawPolygon(QPolygonF() << line.p2() << destArrowP1 << destArrowP2);
|
||||
}
|
||||
78
idasdk76/plugins/qproject/edge.h
Normal file
78
idasdk76/plugins/qproject/edge.h
Normal file
@@ -0,0 +1,78 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
||||
** All rights reserved.
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** This file is part of the examples of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** Commercial Usage
|
||||
** Licensees holding valid Qt Commercial licenses may use this file in
|
||||
** accordance with the Qt Commercial License Agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Nokia.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3.0 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU General Public License version 3.0 requirements will be
|
||||
** met: http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef EDGE_H
|
||||
#define EDGE_H
|
||||
|
||||
#include <QGraphicsItem>
|
||||
|
||||
class Node;
|
||||
|
||||
class Edge : public QGraphicsItem
|
||||
{
|
||||
public:
|
||||
Edge(Node *sourceNode, Node *destNode);
|
||||
~Edge();
|
||||
|
||||
Node *sourceNode() const;
|
||||
void setSourceNode(Node *node);
|
||||
|
||||
Node *destNode() const;
|
||||
void setDestNode(Node *node);
|
||||
|
||||
void adjust();
|
||||
|
||||
enum { Type = UserType + 2 };
|
||||
int type() const override { return Type; }
|
||||
|
||||
protected:
|
||||
QRectF boundingRect() const override;
|
||||
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
|
||||
|
||||
private:
|
||||
Node *source, *dest;
|
||||
|
||||
QPointF sourcePoint;
|
||||
QPointF destPoint;
|
||||
qreal arrowSize;
|
||||
};
|
||||
|
||||
#endif
|
||||
235
idasdk76/plugins/qproject/graphwidget.cpp
Normal file
235
idasdk76/plugins/qproject/graphwidget.cpp
Normal file
@@ -0,0 +1,235 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
||||
** All rights reserved.
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** This file is part of the examples of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** Commercial Usage
|
||||
** Licensees holding valid Qt Commercial licenses may use this file in
|
||||
** accordance with the Qt Commercial License Agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Nokia.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3.0 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU General Public License version 3.0 requirements will be
|
||||
** met: http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "graphwidget.h"
|
||||
#include "edge.h"
|
||||
#include "node.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QGraphicsScene>
|
||||
#include <QWheelEvent>
|
||||
#include <QTime>
|
||||
|
||||
#include <math.h>
|
||||
|
||||
//lint -e429 custodial pointer '' likely not freed nor returned
|
||||
//lint -e665 unparenthesized parameter
|
||||
//lint -e666 expression with side effects passed to repeated parameter
|
||||
//lint -e1524 new in constructor for class '' which has no explicit destructor
|
||||
//lint -e1793 invoking non-const member function
|
||||
|
||||
GraphWidget::GraphWidget()
|
||||
: timerId(0)
|
||||
{
|
||||
qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));
|
||||
|
||||
QGraphicsScene *_scene = new QGraphicsScene(this);
|
||||
_scene->setItemIndexMethod(QGraphicsScene::NoIndex);
|
||||
_scene->setSceneRect(-400, -400, 800, 800);
|
||||
setScene(_scene);
|
||||
setCacheMode(CacheBackground);
|
||||
setViewportUpdateMode(BoundingRectViewportUpdate);
|
||||
setRenderHint(QPainter::Antialiasing);
|
||||
setTransformationAnchor(AnchorUnderMouse);
|
||||
setResizeAnchor(AnchorViewCenter);
|
||||
|
||||
Node *node1 = new Node(this);
|
||||
Node *node2 = new Node(this);
|
||||
Node *node3 = new Node(this);
|
||||
Node *node4 = new Node(this);
|
||||
centerNode = new Node(this);
|
||||
Node *node6 = new Node(this);
|
||||
Node *node7 = new Node(this);
|
||||
Node *node8 = new Node(this);
|
||||
Node *node9 = new Node(this);
|
||||
_scene->addItem(node1);
|
||||
_scene->addItem(node2);
|
||||
_scene->addItem(node3);
|
||||
_scene->addItem(node4);
|
||||
_scene->addItem(centerNode);
|
||||
_scene->addItem(node6);
|
||||
_scene->addItem(node7);
|
||||
_scene->addItem(node8);
|
||||
_scene->addItem(node9);
|
||||
_scene->addItem(new Edge(centerNode, node1));
|
||||
_scene->addItem(new Edge(centerNode, node2));
|
||||
_scene->addItem(new Edge(centerNode, node3));
|
||||
_scene->addItem(new Edge(centerNode, node4));
|
||||
_scene->addItem(new Edge(centerNode, node6));
|
||||
_scene->addItem(new Edge(centerNode, node7));
|
||||
_scene->addItem(new Edge(centerNode, node8));
|
||||
_scene->addItem(new Edge(centerNode, node9));
|
||||
|
||||
node1->setPos(-100, -100);
|
||||
node2->setPos(0, -100);
|
||||
node3->setPos(100, -100);
|
||||
node4->setPos(-100, 0);
|
||||
centerNode->setPos(0, 0);
|
||||
node6->setPos(100, 0);
|
||||
node7->setPos(-100, 100);
|
||||
node8->setPos(0, 100);
|
||||
node9->setPos(100, 100);
|
||||
|
||||
scale(qreal(0.8), qreal(0.8));
|
||||
setMinimumSize(400, 400);
|
||||
setWindowTitle(tr("Elastic IDA Nodes"));
|
||||
}
|
||||
|
||||
void GraphWidget::itemMoved()
|
||||
{
|
||||
if ( !timerId )
|
||||
timerId = startTimer(10);
|
||||
}
|
||||
|
||||
void GraphWidget::keyPressEvent(QKeyEvent *_event)
|
||||
{
|
||||
switch ( _event->key() )
|
||||
{
|
||||
case Qt::Key_Up:
|
||||
centerNode->moveBy(0, -20);
|
||||
break;
|
||||
case Qt::Key_Down:
|
||||
centerNode->moveBy(0, 20);
|
||||
break;
|
||||
case Qt::Key_Left:
|
||||
centerNode->moveBy(-20, 0);
|
||||
break;
|
||||
case Qt::Key_Right:
|
||||
centerNode->moveBy(20, 0);
|
||||
break;
|
||||
case Qt::Key_Plus:
|
||||
scaleView(qreal(1.2));
|
||||
break;
|
||||
case Qt::Key_Minus:
|
||||
scaleView(1 / qreal(1.2));
|
||||
break;
|
||||
case Qt::Key_Space:
|
||||
case Qt::Key_Enter:
|
||||
foreach ( QGraphicsItem *item, scene()->items() )
|
||||
{
|
||||
if ( qgraphicsitem_cast<Node *>(item) )
|
||||
item->setPos(-150 + qrand() % 300, -150 + qrand() % 300);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
QGraphicsView::keyPressEvent(_event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void GraphWidget::timerEvent(QTimerEvent *_event)
|
||||
{
|
||||
Q_UNUSED(_event);
|
||||
|
||||
QList<Node *> nodes;
|
||||
foreach ( QGraphicsItem *item, scene()->items() )
|
||||
{
|
||||
if ( Node *node = qgraphicsitem_cast<Node *>(item) )
|
||||
nodes << node;
|
||||
}
|
||||
|
||||
foreach ( Node *node, nodes )
|
||||
node->calculateForces();
|
||||
|
||||
bool itemsMoved = false;
|
||||
foreach ( Node *node, nodes )
|
||||
{
|
||||
if ( node->_advance() )
|
||||
itemsMoved = true;
|
||||
}
|
||||
|
||||
if ( !itemsMoved )
|
||||
{
|
||||
killTimer(timerId);
|
||||
timerId = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void GraphWidget::wheelEvent(QWheelEvent *_event)
|
||||
{
|
||||
scaleView(pow((double)2, -_event->delta() / 240.0));
|
||||
}
|
||||
|
||||
void GraphWidget::drawBackground(QPainter *painter, const QRectF &_rect)
|
||||
{
|
||||
Q_UNUSED(_rect);
|
||||
|
||||
// Shadow
|
||||
QRectF _sceneRect = this->sceneRect();
|
||||
QRectF rightShadow(_sceneRect.right(), _sceneRect.top() + 5, 5, _sceneRect.height());
|
||||
QRectF bottomShadow(_sceneRect.left() + 5, _sceneRect.bottom(), _sceneRect.width(), 5);
|
||||
if ( rightShadow.intersects(_rect) || rightShadow.contains(_rect) )
|
||||
painter->fillRect(rightShadow, Qt::darkGray);
|
||||
if ( bottomShadow.intersects(_rect) || bottomShadow.contains(_rect) )
|
||||
painter->fillRect(bottomShadow, Qt::darkGray);
|
||||
|
||||
// Fill
|
||||
QLinearGradient gradient(_sceneRect.topLeft(), _sceneRect.bottomRight());
|
||||
gradient.setColorAt(0, Qt::white);
|
||||
gradient.setColorAt(1, Qt::lightGray);
|
||||
painter->fillRect(_rect.intersected(_sceneRect), gradient);
|
||||
painter->setBrush(Qt::NoBrush);
|
||||
painter->drawRect(_sceneRect);
|
||||
|
||||
// Text
|
||||
QRectF textRect(_sceneRect.left() + 4, _sceneRect.top() + 4,
|
||||
_sceneRect.width() - 4, _sceneRect.height() - 4);
|
||||
QString message(tr("Click and drag the nodes around, and zoom with the mouse "
|
||||
"wheel or the '+' and '-' keys"));
|
||||
|
||||
QFont _font = painter->font();
|
||||
_font.setBold(true);
|
||||
_font.setPointSize(14);
|
||||
painter->setFont(_font);
|
||||
painter->setPen(Qt::lightGray);
|
||||
painter->drawText(textRect.translated(2, 2), message);
|
||||
painter->setPen(Qt::black);
|
||||
painter->drawText(textRect, message);
|
||||
}
|
||||
|
||||
void GraphWidget::scaleView(qreal scaleFactor)
|
||||
{
|
||||
qreal factor = matrix().scale(scaleFactor, scaleFactor).mapRect(QRectF(0, 0, 1, 1)).width();
|
||||
if ( factor < 0.07 || factor > 100 )
|
||||
return;
|
||||
|
||||
scale(scaleFactor, scaleFactor);
|
||||
}
|
||||
73
idasdk76/plugins/qproject/graphwidget.h
Normal file
73
idasdk76/plugins/qproject/graphwidget.h
Normal file
@@ -0,0 +1,73 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
||||
** All rights reserved.
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** This file is part of the examples of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** Commercial Usage
|
||||
** Licensees holding valid Qt Commercial licenses may use this file in
|
||||
** accordance with the Qt Commercial License Agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Nokia.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3.0 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU General Public License version 3.0 requirements will be
|
||||
** met: http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef GRAPHWIDGET_H
|
||||
#define GRAPHWIDGET_H
|
||||
|
||||
#include <QGraphicsView>
|
||||
|
||||
//lint -esym(818, _o, _a) Pointer parameter '' could be declared as pointing to const
|
||||
|
||||
class Node;
|
||||
|
||||
class GraphWidget : public QGraphicsView
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
GraphWidget();
|
||||
|
||||
void itemMoved();
|
||||
|
||||
protected:
|
||||
void keyPressEvent(QKeyEvent *event) override;
|
||||
void timerEvent(QTimerEvent *event) override;
|
||||
void wheelEvent(QWheelEvent *event) override;
|
||||
void drawBackground(QPainter *painter, const QRectF &rect) override;
|
||||
|
||||
void scaleView(qreal scaleFactor);
|
||||
|
||||
private:
|
||||
int timerId;
|
||||
Node *centerNode;
|
||||
};
|
||||
|
||||
#endif
|
||||
18
idasdk76/plugins/qproject/makefile
Normal file
18
idasdk76/plugins/qproject/makefile
Normal file
@@ -0,0 +1,18 @@
|
||||
PROC=qproject
|
||||
O1=moc_graphwidget
|
||||
O2=graphwidget
|
||||
O3=node
|
||||
O4=edge
|
||||
|
||||
include ../qtplugin.mak
|
||||
|
||||
# MAKEDEP dependency list ------------------
|
||||
$(F)edge$(O) : edge.cpp edge.h node.h
|
||||
$(F)graphwidget$(O): edge.h graphwidget.cpp graphwidget.h node.h
|
||||
$(F)moc_graphwidget$(O): $(F)moc_graphwidget.cpp graphwidget.h
|
||||
$(F)node$(O) : edge.h graphwidget.h node.cpp node.h
|
||||
$(F)qproject$(O): $(I)bitrange.hpp $(I)bytes.hpp $(I)config.hpp $(I)fpro.h \
|
||||
$(I)funcs.hpp $(I)ida.hpp $(I)idp.hpp $(I)kernwin.hpp \
|
||||
$(I)lines.hpp $(I)llong.hpp $(I)loader.hpp $(I)nalt.hpp \
|
||||
$(I)netnode.hpp $(I)pro.h $(I)range.hpp $(I)segment.hpp \
|
||||
$(I)ua.hpp $(I)xref.hpp graphwidget.h qproject.cpp
|
||||
175
idasdk76/plugins/qproject/node.cpp
Normal file
175
idasdk76/plugins/qproject/node.cpp
Normal file
@@ -0,0 +1,175 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
||||
** All rights reserved.
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** This file is part of the examples of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** Commercial Usage
|
||||
** Licensees holding valid Qt Commercial licenses may use this file in
|
||||
** accordance with the Qt Commercial License Agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Nokia.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3.0 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU General Public License version 3.0 requirements will be
|
||||
** met: http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include <QGraphicsScene>
|
||||
#include <QGraphicsSceneMouseEvent>
|
||||
#include <QPainter>
|
||||
#include <QStyleOption>
|
||||
|
||||
#include "edge.h"
|
||||
#include "node.h"
|
||||
#include "graphwidget.h"
|
||||
|
||||
//lint -e665 unparenthesized parameter
|
||||
//lint -e666 expression with side effects passed to repeated parameter
|
||||
//lint -e790 possibly truncated multiplication
|
||||
|
||||
const char html[] =
|
||||
"<span style=\"white-space: pre; font-family: FixedSys; color: blue; background: white\">"
|
||||
"<span style=\"color:navy\">push </span><span style=\"color:green\">0</span>\n"
|
||||
"<span style=\"color:navy\">push [ebp+</span><span style=\"color:green\">argv</span><span style=\"color:navy\">]</span>\n"
|
||||
"<span style=\"color:navy\">call sub_4015B8</span>";
|
||||
|
||||
Node::Node(GraphWidget *graphWidget)
|
||||
: graph(graphWidget)
|
||||
{
|
||||
setFlag(ItemIsMovable);
|
||||
setFlag(ItemIsFocusable);
|
||||
setFlag(ItemIsSelectable);
|
||||
setFlag(ItemSendsGeometryChanges);
|
||||
setCacheMode(DeviceCoordinateCache);
|
||||
setZValue(-1);
|
||||
setHtml(html);
|
||||
}
|
||||
|
||||
void Node::addEdge(Edge *edge)
|
||||
{
|
||||
edgeList << edge;
|
||||
edge->adjust();
|
||||
}
|
||||
|
||||
QList<Edge *> Node::edges() const
|
||||
{
|
||||
return edgeList;
|
||||
}
|
||||
|
||||
void Node::calculateForces()
|
||||
{
|
||||
if ( !scene() || scene()->mouseGrabberItem() == this )
|
||||
{
|
||||
newPos = pos();
|
||||
return;
|
||||
}
|
||||
|
||||
// Sum up all forces pushing this item away
|
||||
qreal xvel = 0;
|
||||
qreal yvel = 0;
|
||||
foreach ( QGraphicsItem *item, scene()->items() )
|
||||
{
|
||||
Node *node = qgraphicsitem_cast<Node *>(item);
|
||||
if ( !node )
|
||||
continue;
|
||||
|
||||
QLineF line(mapFromItem(node, 0, 0), QPointF(0, 0));
|
||||
qreal dx = line.dx();
|
||||
qreal dy = line.dy();
|
||||
double l = 2.0 * (dx * dx + dy * dy);
|
||||
if ( l > 0 )
|
||||
{
|
||||
xvel += (dx * 150.0) / l;
|
||||
yvel += (dy * 150.0) / l;
|
||||
}
|
||||
}
|
||||
|
||||
// Now subtract all forces pulling items together
|
||||
double weight = (edgeList.size() + 1) * 100;
|
||||
foreach ( Edge *edge, edgeList )
|
||||
{
|
||||
QPointF _pos;
|
||||
if ( edge->sourceNode() == this )
|
||||
_pos = mapFromItem(edge->destNode(), 0, 0);
|
||||
else
|
||||
_pos = mapFromItem(edge->sourceNode(), 0, 0);
|
||||
xvel += _pos.x() / weight;
|
||||
yvel += _pos.y() / weight;
|
||||
}
|
||||
|
||||
if ( qAbs(xvel) < 0.1 && qAbs(yvel) < 0.1 )
|
||||
xvel = yvel = 0;
|
||||
|
||||
QRectF sceneRect = scene()->sceneRect();
|
||||
newPos = pos() + QPointF(xvel, yvel);
|
||||
newPos.setX(qMin(qMax(newPos.x(), sceneRect.left() + 10), sceneRect.right() - 10));
|
||||
newPos.setY(qMin(qMax(newPos.y(), sceneRect.top() + 10), sceneRect.bottom() - 10));
|
||||
}
|
||||
|
||||
bool Node::_advance()
|
||||
{
|
||||
if ( newPos == pos() )
|
||||
return false;
|
||||
|
||||
setPos(newPos);
|
||||
return true;
|
||||
}
|
||||
|
||||
QVariant Node::itemChange(GraphicsItemChange change, const QVariant &value)
|
||||
{
|
||||
switch ( change )
|
||||
{
|
||||
case ItemPositionHasChanged:
|
||||
foreach ( Edge *edge, edgeList )
|
||||
edge->adjust();
|
||||
graph->itemMoved();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return QGraphicsTextItem::itemChange(change, value);
|
||||
}
|
||||
|
||||
void Node::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
|
||||
{
|
||||
painter->fillRect(option->rect, Qt::white);
|
||||
QGraphicsTextItem::paint(painter, option, widget);
|
||||
}
|
||||
|
||||
void Node::mousePressEvent(QGraphicsSceneMouseEvent *_event)
|
||||
{
|
||||
update();
|
||||
QGraphicsTextItem::mousePressEvent(_event);
|
||||
}
|
||||
|
||||
void Node::mouseReleaseEvent(QGraphicsSceneMouseEvent *_event)
|
||||
{
|
||||
update();
|
||||
QGraphicsTextItem::mouseReleaseEvent(_event);
|
||||
}
|
||||
81
idasdk76/plugins/qproject/node.h
Normal file
81
idasdk76/plugins/qproject/node.h
Normal file
@@ -0,0 +1,81 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
||||
** All rights reserved.
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** This file is part of the examples of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** Commercial Usage
|
||||
** Licensees holding valid Qt Commercial licenses may use this file in
|
||||
** accordance with the Qt Commercial License Agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Nokia.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3.0 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU General Public License version 3.0 requirements will be
|
||||
** met: http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef NODE_H
|
||||
#define NODE_H
|
||||
|
||||
#include <QGraphicsTextItem>
|
||||
#include <QList>
|
||||
|
||||
class Edge;
|
||||
class GraphWidget;
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QGraphicsSceneMouseEvent;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class Node : public QGraphicsTextItem
|
||||
{
|
||||
public:
|
||||
Node(GraphWidget *graphWidget);
|
||||
|
||||
void addEdge(Edge *edge);
|
||||
QList<Edge *> edges() const;
|
||||
|
||||
enum { Type = UserType + 1 };
|
||||
int type() const override { return Type; }
|
||||
|
||||
void calculateForces();
|
||||
bool _advance();
|
||||
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0) override;
|
||||
|
||||
protected:
|
||||
QVariant itemChange(GraphicsItemChange change, const QVariant &value) override;
|
||||
|
||||
void mousePressEvent(QGraphicsSceneMouseEvent *event) override;
|
||||
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override;
|
||||
|
||||
private:
|
||||
QList<Edge *> edgeList;
|
||||
QPointF newPos;
|
||||
GraphWidget *graph;
|
||||
};
|
||||
|
||||
#endif
|
||||
135
idasdk76/plugins/qproject/qproject.cpp
Normal file
135
idasdk76/plugins/qproject/qproject.cpp
Normal file
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* This is a sample plugin module. It demonstrates how to fully use
|
||||
* the Qt environment in IDA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <QtGui>
|
||||
#include <QtWidgets>
|
||||
|
||||
#include <ida.hpp>
|
||||
#include <idp.hpp>
|
||||
#include <loader.hpp>
|
||||
#include <kernwin.hpp>
|
||||
|
||||
// include your own widget here
|
||||
#include "graphwidget.h"
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
struct plugin_ctx_t : public plugmod_t, public event_listener_t
|
||||
{
|
||||
TWidget *widget = nullptr;
|
||||
|
||||
plugin_ctx_t()
|
||||
{
|
||||
hook_event_listener(HT_UI, this);
|
||||
}
|
||||
~plugin_ctx_t()
|
||||
{
|
||||
// listeners are uninstalled automatically
|
||||
// when the owner module is unloaded
|
||||
widget = nullptr; // make lint happy
|
||||
}
|
||||
|
||||
virtual bool idaapi run(size_t) override;
|
||||
virtual ssize_t idaapi on_event(ssize_t code, va_list va) override;
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
ssize_t idaapi plugin_ctx_t::on_event(ssize_t code, va_list va)
|
||||
{
|
||||
if ( code == ui_widget_visible )
|
||||
{
|
||||
TWidget *l_widget = va_arg(va, TWidget *);
|
||||
if ( l_widget == widget )
|
||||
{
|
||||
// widget is created, create controls
|
||||
|
||||
QWidget *w = (QWidget *) widget;
|
||||
|
||||
QHBoxLayout *mainLayout = new QHBoxLayout();
|
||||
mainLayout->setMargin(0);
|
||||
|
||||
GraphWidget *userWidget = new GraphWidget();
|
||||
|
||||
mainLayout->addWidget(userWidget);
|
||||
|
||||
w->setLayout(mainLayout);
|
||||
//lint -e429 mainLayout not freed
|
||||
}
|
||||
}
|
||||
if ( code == ui_widget_invisible )
|
||||
{
|
||||
TWidget *l_widget = va_arg(va, TWidget *);
|
||||
if ( l_widget == widget )
|
||||
{
|
||||
// widget is closed, destroy objects (if required)
|
||||
widget = nullptr;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
bool idaapi plugin_ctx_t::run(size_t)
|
||||
{
|
||||
TWidget *g_widget = find_widget("Sample Qt Project");
|
||||
if ( g_widget == nullptr )
|
||||
{
|
||||
widget = create_empty_widget("Sample Qt Project");
|
||||
display_widget(widget, WOPN_DP_TAB|WOPN_RESTORE);
|
||||
}
|
||||
else
|
||||
{
|
||||
close_widget(g_widget, WCLS_SAVE);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static plugmod_t *idaapi init()
|
||||
{
|
||||
if ( !is_idaq() )
|
||||
return nullptr;
|
||||
return new plugin_ctx_t;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
char comment[] = "This is a sample Qt Project plugin.";
|
||||
|
||||
char help[] =
|
||||
"A sample plugin module\n"
|
||||
"\n"
|
||||
"This module shows you how to use fully the Qt environment in IDA.";
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// This is the preferred name of the plugin module in the menu system
|
||||
// The preferred name may be overridden in plugins.cfg file
|
||||
|
||||
char wanted_name[] = "Qt Project Sample";
|
||||
|
||||
|
||||
// This is the preferred hotkey for the plugin module
|
||||
// The preferred hotkey may be overridden in plugins.cfg file
|
||||
|
||||
char wanted_hotkey[] = "";
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// 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
|
||||
help, // multiline help about the plugin
|
||||
wanted_name, // the preferred short name of the plugin
|
||||
wanted_hotkey, // the preferred hotkey to run the plugin
|
||||
};
|
||||
65
idasdk76/plugins/qtplugin.mak
Normal file
65
idasdk76/plugins/qtplugin.mak
Normal file
@@ -0,0 +1,65 @@
|
||||
include ../plugin.mak
|
||||
|
||||
CC_DEFS += QT_CORE_LIB
|
||||
CC_DEFS += QT_DLL
|
||||
CC_DEFS += QT_GUI_LIB
|
||||
CC_DEFS += QT_NAMESPACE=QT
|
||||
CC_DEFS += QT_THREAD_SUPPORT
|
||||
CC_DEFS += QT_WIDGETS_LIB
|
||||
CC_INCP += .
|
||||
ifdef __LINUX__
|
||||
CC_F += -fPIC
|
||||
else ifdef __NT__
|
||||
CFLAGS += /GS
|
||||
CFLAGS += /wd4946 # reinterpret_cast used between related classes
|
||||
CFLAGS += /wd4826 # Conversion from 'ptr32' to 'int64' is sign-extended. This may cause unexpected runtime behavior.
|
||||
CFLAGS += /wd4628 # Digraphs not supported. Avoids errors on things such as: "template<> inline void swap<::QT::QByteArray>"
|
||||
CFLAGS += /wd4718 # 'QT::QMapNode<int,int>::destroySubTree' : recursive call has no side effects, deleting
|
||||
CFLAGS += /wd4481 # warning C4481: nonstandard extension used: override specifier 'override'
|
||||
endif
|
||||
|
||||
ifdef __MAC__
|
||||
PREF=$(QTDIR)lib/
|
||||
CC_INCP += $(PREF)QtCore.framework/Headers
|
||||
CC_INCP += $(PREF)QtGui.framework/Headers
|
||||
CC_INCP += $(PREF)QtWidgets.framework/Headers
|
||||
CFLAGS += -F$(PREF)
|
||||
LIBS += $(PREF)QtCore.framework/QtCore
|
||||
LIBS += $(PREF)QtGui.framework/QtGui
|
||||
LIBS += $(PREF)QtWidgets.framework/QtWidgets
|
||||
# We must change the library path in the plugin so they become relative
|
||||
# to the ida executable. Otherwise the plugin loads the second copy of
|
||||
# these libraries and crashes IDA
|
||||
CHANGE_LIBPATH=install_name_tool -change \
|
||||
$(QTDIR)lib/$1.framework/Versions/4/$1 \
|
||||
@executable_path/../Frameworks/$1.framework/Versions/4/$1 $@
|
||||
POSTACTION=@$(call CHANGE_LIBPATH,QtGui); \
|
||||
$(call CHANGE_LIBPATH,QtWidgets); \
|
||||
$(call CHANGE_LIBPATH,QtCore)
|
||||
else
|
||||
CC_INCP += $(QTDIR)include
|
||||
CC_INCP += $(QTDIR)include/QtCore
|
||||
CC_INCP += $(QTDIR)include/QtGui
|
||||
CC_INCP += $(QTDIR)include/QtWidgets
|
||||
ifdef __LINUX__
|
||||
PREF=$(QTDIR)lib/lib
|
||||
POST=.so
|
||||
endif # __LINUX__
|
||||
ifdef __NT__
|
||||
PREF=$(QTDIR)lib/
|
||||
ifdef NDEBUG
|
||||
POST=$(A)
|
||||
else
|
||||
POST=d$(A)
|
||||
endif
|
||||
endif
|
||||
LIBS += $(PREF)Qt5Core$(POST)
|
||||
LIBS += $(PREF)Qt5Gui$(POST)
|
||||
LIBS += $(PREF)Qt5Widgets$(POST)
|
||||
endif
|
||||
|
||||
$(F)moc_%.cpp: %.h
|
||||
$(QTDIR)bin/moc -I. $< > $@
|
||||
|
||||
# Add $(F) to vpath for $(F)moc_*$(O).
|
||||
vpath %.cpp $(F)
|
||||
13
idasdk76/plugins/qwindow/makefile
Normal file
13
idasdk76/plugins/qwindow/makefile
Normal file
@@ -0,0 +1,13 @@
|
||||
PROC=qwindow
|
||||
O1=moc_myactions
|
||||
|
||||
include ../qtplugin.mak
|
||||
|
||||
# MAKEDEP dependency list ------------------
|
||||
$(F)moc_myactions$(O): $(F)moc_myactions.cpp myactions.h
|
||||
$(F)qwindow$(O) : $(I)bitrange.hpp $(I)bytes.hpp $(I)config.hpp $(I)fpro.h \
|
||||
$(I)funcs.hpp $(I)ida.hpp $(I)idp.hpp $(I)ieee.h \
|
||||
$(I)kernwin.hpp $(I)lines.hpp $(I)llong.hpp \
|
||||
$(I)loader.hpp $(I)nalt.hpp $(I)netnode.hpp $(I)pro.h \
|
||||
$(I)range.hpp $(I)segment.hpp $(I)ua.hpp $(I)xref.hpp \
|
||||
qwindow.cpp
|
||||
14
idasdk76/plugins/qwindow/myactions.h
Normal file
14
idasdk76/plugins/qwindow/myactions.h
Normal file
@@ -0,0 +1,14 @@
|
||||
|
||||
#include <QtWidgets>
|
||||
|
||||
class MyActions : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
MyActions(QObject *_parent) : QObject(_parent) {}
|
||||
|
||||
private slots:
|
||||
void clicked();
|
||||
|
||||
};
|
||||
148
idasdk76/plugins/qwindow/qwindow.cpp
Normal file
148
idasdk76/plugins/qwindow/qwindow.cpp
Normal file
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* This is a sample plugin module. It demonstrates how to create your
|
||||
* own window and populate it with Qt widgets.
|
||||
*
|
||||
* Note: we discourage using this plugin and using Qt widgets from C++.
|
||||
* Such plugins will depends on the exact version of the Qt libraries
|
||||
* and C++ compiler used to build them. Hex-Rays may change
|
||||
* both Qt libraries and C++ compiler at any time used to build IDA,
|
||||
* without an advance warning. Second, IDA uses a custom build of
|
||||
* the Qt libraries, with a namespace.
|
||||
* Please consider using PyQt to create Qt widgets, it is more robust
|
||||
* and does not suffer from these problems.
|
||||
*/
|
||||
|
||||
#include <QtWidgets>
|
||||
|
||||
#include <ida.hpp>
|
||||
#include <idp.hpp>
|
||||
#include <loader.hpp>
|
||||
#include <kernwin.hpp>
|
||||
|
||||
#include "myactions.h"
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//lint -e1762
|
||||
void MyActions::clicked()
|
||||
{
|
||||
info("Button is clicked");
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
struct plugin_ctx_t : public plugmod_t, public event_listener_t
|
||||
{
|
||||
TWidget *widget = nullptr;
|
||||
|
||||
plugin_ctx_t()
|
||||
{
|
||||
hook_event_listener(HT_UI, this);
|
||||
}
|
||||
~plugin_ctx_t()
|
||||
{
|
||||
// listeners are uninstalled automatically
|
||||
// when the owner module is unloaded
|
||||
widget = nullptr; // make lint happy
|
||||
}
|
||||
|
||||
virtual bool idaapi run(size_t) override;
|
||||
virtual ssize_t idaapi on_event(ssize_t code, va_list va) override;
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
ssize_t idaapi plugin_ctx_t::on_event(ssize_t code, va_list va)
|
||||
{
|
||||
if ( code == ui_widget_visible )
|
||||
{
|
||||
TWidget *l_widget = va_arg(va, TWidget *);
|
||||
if ( l_widget == widget )
|
||||
{
|
||||
QWidget *w = (QWidget *) widget;
|
||||
MyActions *actions = new MyActions(w);
|
||||
|
||||
// create a widget
|
||||
QPushButton *b = new QPushButton("Click here", w);
|
||||
|
||||
// connect the button to a slot
|
||||
QObject::connect(b, SIGNAL(clicked()), actions, SLOT(clicked())); //lint !e2666 expression with side effects
|
||||
|
||||
// position and display it
|
||||
b->move(50, 50);
|
||||
b->show();
|
||||
msg("Qt widget is displayed\n");
|
||||
//lint -esym(429, actions, b) not freed
|
||||
}
|
||||
}
|
||||
else if ( code == ui_widget_invisible )
|
||||
{
|
||||
TWidget *l_widget = va_arg(va, TWidget *);
|
||||
if ( l_widget == widget )
|
||||
{
|
||||
// user defined widget is closed, destroy its controls
|
||||
// (to be implemented)
|
||||
msg("Qt widget is closed\n");
|
||||
widget = nullptr;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
bool idaapi plugin_ctx_t::run(size_t)
|
||||
{
|
||||
TWidget *g_widget = find_widget("Sample Qt subwindow");
|
||||
if ( g_widget == nullptr )
|
||||
{
|
||||
widget = create_empty_widget("Sample Qt subwindow");
|
||||
display_widget(widget, WOPN_DP_TAB|WOPN_RESTORE);
|
||||
}
|
||||
else
|
||||
{
|
||||
close_widget(g_widget, WCLS_SAVE);
|
||||
widget = nullptr; // make lint happy
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static plugmod_t *idaapi init()
|
||||
{
|
||||
if ( !is_idaq() )
|
||||
return nullptr;
|
||||
return new plugin_ctx_t;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static const char comment[] = "This is a sample Qt plugin.";
|
||||
static const char help[] =
|
||||
"A sample plugin module\n"
|
||||
"\n"
|
||||
"This module shows you how to create a Qt window.";
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// This is the preferred name of the plugin module in the menu system
|
||||
// The preferred name may be overridden in plugins.cfg file
|
||||
|
||||
static const char wanted_name[] = "Create Qt subwindow";
|
||||
|
||||
// This is the preferred hotkey for the plugin module
|
||||
// The preferred hotkey may be overridden in plugins.cfg file
|
||||
|
||||
static const char wanted_hotkey[] = "";
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// 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
|
||||
help, // multiline help about the plugin
|
||||
wanted_name, // the preferred short name of the plugin
|
||||
wanted_hotkey, // the preferred hotkey to run the plugin
|
||||
};
|
||||
34
idasdk76/plugins/readme.txt
Normal file
34
idasdk76/plugins/readme.txt
Normal file
@@ -0,0 +1,34 @@
|
||||
|
||||
|
||||
This directory contains sample plugin modules for IDA.
|
||||
|
||||
Plugin modules are accessible by the user in two ways:
|
||||
|
||||
- they appear as menu items in menu Edit|Plugins
|
||||
- they can be invoked by hotkeys
|
||||
|
||||
A plugin has full access to the database and can interact with
|
||||
the user.
|
||||
|
||||
IDA looks for plugins in PLUGINS subdirectory.
|
||||
In this directory there is also a configuration file.
|
||||
It is not necessary for a plugin to appear in the configuration file.
|
||||
Even if a plugin is not there IDA will load it.
|
||||
The configuration file allows the user to reassign the hotkeys,
|
||||
to change the plugin name as it appears in the menu or to change
|
||||
the argument passed to the plugin.
|
||||
|
||||
A plugin has one exported entry (it should have the "PLUGIN" name).
|
||||
The entry is a plugin descriptor (plugin_t).
|
||||
It contains pointers to the following functions:
|
||||
|
||||
- init: is called when the plugin is loaded
|
||||
- run: is called when the user calls the plugin
|
||||
- term: is called before the plugin is unloaded
|
||||
|
||||
run() function is the function which will do the real work.
|
||||
It has full access to the database (see include files for the
|
||||
description of IDA API). Also it can interact with the user
|
||||
(most of these functions are in kernwin.hpp file).
|
||||
|
||||
|
||||
20
idasdk76/plugins/script_plg.mak
Normal file
20
idasdk76/plugins/script_plg.mak
Normal file
@@ -0,0 +1,20 @@
|
||||
|
||||
ifdef EXAMPLE
|
||||
BIN_PATH = $(R)plugins-examples/
|
||||
else
|
||||
BIN_PATH = $(R)plugins/
|
||||
endif
|
||||
|
||||
INSTALLED_SCRIPTS = $(addprefix $(BIN_PATH), $(SCRIPTS))
|
||||
|
||||
all: $(INSTALLED_SCRIPTS)
|
||||
|
||||
$(BIN_PATH)%.py: %.py
|
||||
$(Q)$(CP) $? $@
|
||||
$(BIN_PATH)%.idc: %.idc
|
||||
$(Q)$(CP) $? $@
|
||||
|
||||
.PHONY: uninstall
|
||||
uninstall::
|
||||
rm -rf $(INSTALLED_SCRIPTS)
|
||||
|
||||
52
idasdk76/plugins/script_plg/idcplugin.idc
Normal file
52
idasdk76/plugins/script_plg/idcplugin.idc
Normal file
@@ -0,0 +1,52 @@
|
||||
#include <idc.idc>
|
||||
|
||||
class myplugmod_t
|
||||
{
|
||||
myplugmod_t()
|
||||
{
|
||||
this.wanted_name = "Sample IDC plugin";
|
||||
}
|
||||
run(arg)
|
||||
{
|
||||
msg("%s: run() has been called with %d\n", this.wanted_name, arg);
|
||||
return (arg % 2) == 0;
|
||||
}
|
||||
~myplugmod_t()
|
||||
{
|
||||
msg("%s: unloaded\n", this.wanted_name);
|
||||
}
|
||||
}
|
||||
|
||||
class myplugin_t
|
||||
{
|
||||
myplugin_t()
|
||||
{
|
||||
this.flags = PLUGIN_MULTI;
|
||||
this.comment = "This is a sample IDC plugin";
|
||||
this.help = "This is help";
|
||||
this.wanted_name = "Sample IDC plugin";
|
||||
this.wanted_hotkey = "Alt-F6";
|
||||
}
|
||||
|
||||
init()
|
||||
{
|
||||
msg("%s: init() has been called\n", this.wanted_name);
|
||||
return myplugmod_t();
|
||||
}
|
||||
|
||||
run(arg)
|
||||
{
|
||||
msg("%s: ERROR: run() has been called for global object!\n", this.wanted_name);
|
||||
return (arg % 2) == 0;
|
||||
}
|
||||
|
||||
term()
|
||||
{
|
||||
msg("%s: ERROR: term() has been called (should never be called)\n", this.wanted_name);
|
||||
}
|
||||
}
|
||||
|
||||
static PLUGIN_ENTRY()
|
||||
{
|
||||
return myplugin_t();
|
||||
}
|
||||
9
idasdk76/plugins/script_plg/makefile
Normal file
9
idasdk76/plugins/script_plg/makefile
Normal file
@@ -0,0 +1,9 @@
|
||||
|
||||
include ../../allmake.mak
|
||||
|
||||
SCRIPTS += idcplugin.idc
|
||||
SCRIPTS += pyplugin.py
|
||||
SCRIPTS += procext.py
|
||||
|
||||
include ../script_plg.mak
|
||||
|
||||
69
idasdk76/plugins/script_plg/procext.py
Normal file
69
idasdk76/plugins/script_plg/procext.py
Normal file
@@ -0,0 +1,69 @@
|
||||
import idaapi
|
||||
|
||||
mymnem = "linux_kernel_call"
|
||||
|
||||
"""
|
||||
This is a sample plugin for extending processor modules
|
||||
|
||||
It extends the IBM PC processor module to disassemble
|
||||
"int 80h"
|
||||
as
|
||||
"%s"
|
||||
|
||||
for ELF files
|
||||
|
||||
(c) Hex-Rays
|
||||
""" % mymnem
|
||||
|
||||
NN_kernel_call = idaapi.CUSTOM_INSN_ITYPE
|
||||
|
||||
#--------------------------------------------------------------------------
|
||||
class linux_idp_hook_t(idaapi.IDP_Hooks):
|
||||
def __init__(self):
|
||||
idaapi.IDP_Hooks.__init__(self)
|
||||
|
||||
def ev_ana_insn(self, insn):
|
||||
if idaapi.get_bytes(insn.ea, 2) != b"\xCD\x80":
|
||||
return False
|
||||
insn.itype = NN_kernel_call
|
||||
insn.size = 2
|
||||
return True
|
||||
|
||||
def ev_out_mnem(self, outctx):
|
||||
if outctx.insn.itype != NN_kernel_call:
|
||||
return 0
|
||||
outctx.out_custom_mnem(mymnem)
|
||||
return 1
|
||||
|
||||
#--------------------------------------------------------------------------
|
||||
class linuxprocext_t(idaapi.plugin_t):
|
||||
# Processor fix plugin module
|
||||
flags = idaapi.PLUGIN_PROC | idaapi.PLUGIN_HIDE
|
||||
comment = ""
|
||||
wanted_hotkey = ""
|
||||
help = "Replaces int 0x80 with %s" % mymnem
|
||||
wanted_name = mymnem
|
||||
|
||||
def init(self):
|
||||
self.prochook = None
|
||||
if idaapi.ph_get_id() != idaapi.PLFM_386 or idaapi.cvar.inf.filetype != idaapi.f_ELF:
|
||||
print("linuxprocext_t.init() skipped!")
|
||||
return idaapi.PLUGIN_SKIP
|
||||
|
||||
self.prochook = linux_idp_hook_t()
|
||||
self.prochook.hook()
|
||||
|
||||
print("linuxprocext_t.init() called!")
|
||||
return idaapi.PLUGIN_KEEP
|
||||
|
||||
def run(self, arg):
|
||||
pass
|
||||
|
||||
def term(self):
|
||||
print("linuxprocext_t.term() called!")
|
||||
if self.prochook:
|
||||
self.prochook.unhook()
|
||||
|
||||
#--------------------------------------------------------------------------
|
||||
def PLUGIN_ENTRY():
|
||||
return linuxprocext_t()
|
||||
34
idasdk76/plugins/script_plg/pyplugin.py
Normal file
34
idasdk76/plugins/script_plg/pyplugin.py
Normal file
@@ -0,0 +1,34 @@
|
||||
import ida_idaapi, ida_kernwin
|
||||
|
||||
class myplugmod_t(ida_idaapi.plugmod_t):
|
||||
def __del__(self):
|
||||
ida_kernwin.msg("unloaded myplugmod\n")
|
||||
|
||||
def run(self, arg):
|
||||
ida_kernwin.msg("run() called with %d!\n" % arg)
|
||||
return (arg % 2) == 0
|
||||
|
||||
class myplugin_t(ida_idaapi.plugin_t):
|
||||
flags = ida_idaapi.PLUGIN_UNL | ida_idaapi.PLUGIN_MULTI
|
||||
comment = "This is a sample Python plugin"
|
||||
help = "This is help"
|
||||
wanted_name = "Sample Python plugin"
|
||||
wanted_hotkey = "Alt-F8"
|
||||
|
||||
#def __del__(self):
|
||||
#ida_kernwin.msg("unloaded globally\n")
|
||||
|
||||
def init(self):
|
||||
ida_kernwin.msg("init() called!\n")
|
||||
return myplugmod_t()
|
||||
|
||||
def run(self, arg):
|
||||
ida_kernwin.msg("ERROR: run() called for global object!\n")
|
||||
return (arg % 2) == 0
|
||||
|
||||
def term(self):
|
||||
ida_kernwin.msg("ERROR: term() called (should never be called)\n")
|
||||
|
||||
def PLUGIN_ENTRY():
|
||||
return myplugin_t()
|
||||
|
||||
11
idasdk76/plugins/snapshots/makefile
Normal file
11
idasdk76/plugins/snapshots/makefile
Normal file
@@ -0,0 +1,11 @@
|
||||
PROC=snapshots
|
||||
|
||||
include ../plugin.mak
|
||||
|
||||
# MAKEDEP dependency list ------------------
|
||||
$(F)snapshots$(O): $(I)bitrange.hpp $(I)bytes.hpp $(I)config.hpp \
|
||||
$(I)fpro.h $(I)funcs.hpp $(I)ida.hpp $(I)idp.hpp \
|
||||
$(I)ieee.h $(I)kernwin.hpp $(I)lines.hpp $(I)llong.hpp \
|
||||
$(I)loader.hpp $(I)nalt.hpp $(I)netnode.hpp $(I)pro.h \
|
||||
$(I)range.hpp $(I)segment.hpp $(I)ua.hpp $(I)xref.hpp \
|
||||
snapshots.cpp
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user