forked from idapython/src
-
Notifications
You must be signed in to change notification settings - Fork 5
/
pywraps.hpp
991 lines (857 loc) · 37.3 KB
/
pywraps.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
#ifndef __PYWRAPS_HPP__
#define __PYWRAPS_HPP__
#include <Python.h>
//------------------------------------------------------------------------
// The following are to be used whenever Py_BuildValue-style
// format specifiers are needed.
#define PY_BV_EA "K" // Convert a C unsigned long long to a Python long integer object.
#define PY_BV_SZ "n" // Convert a C Py_ssize_t to a Python integer or long integer.
#define PY_BV_UVAL PY_BV_EA
#define PY_BV_ASIZE PY_BV_EA
#define PY_BV_SEL PY_BV_EA
#define PY_BV_SVAL "L" // Convert a C long long to a Python long integer object
#ifdef PY3
# define PY_BV_TYPE "y"
# define PY_BV_FIELDS "y"
# define PY_BV_BYTES "y"
#else
# define PY_BV_TYPE "s"
# define PY_BV_FIELDS "s"
# define PY_BV_BYTES "s"
#endif
typedef unsigned PY_LONG_LONG bvea_t;
typedef Py_ssize_t bvsz_t;
typedef bvea_t bvuval_t;
typedef bvea_t bvasize_t;
typedef bvea_t bvsel_t;
typedef PY_LONG_LONG bvsval_t;
//-------------------------------------------------------------------------
// a few forward decls
class insn_t;
class op_t;
struct switch_info_t;
// "A pointer can be explicitly converted to any integral type large
// enough to hold it. The mapping function is implementation-defined."
// — C++03
// => G++ (and probably MSVC) will typically first sign-extend the pointer.
//
// int bar(void *p) { return foo(uint64(p)); }
//
// translates to:
//
// mov 0x8(%ebp),%eax
// mov %eax,%edx
// sar $0x1f,%edx ; <---- boom!
// mov %eax,(%esp)
// mov %edx,0x4(%esp)
// call 2d <_Z3barPv+0x16>
#define PTR2U64(Binding) (uint64(Binding))
//------------------------------------------------------------------------
#define S_IDA_IDAAPI_MODNAME "ida_idaapi"
#define S_IDA_NALT_MODNAME "ida_nalt"
#define S_IDA_UA_MODNAME "ida_ua"
#define S_IDA_KERNWIN_MODNAME "ida_kernwin"
#define S_IDA_MOVES_MODNAME "ida_moves"
#define S_IDC_MODNAME "idc"
#define S_IDAAPI_EXECSCRIPT "IDAPython_ExecScript"
#define S_IDAAPI_FINDCOMPLETIONS "IDAPython_Completion"
#define S_IDAAPI_FORMATEXC "IDAPython_FormatExc"
#define S_IDAAPI_LOADPROCMOD "IDAPython_LoadProcMod"
#define S_IDAAPI_UNLOADPROCMOD "IDAPython_UnLoadProcMod"
//------------------------------------------------------------------------
// String constants used
static const char S_PYINVOKE0[] = "_py_invoke0";
static const char S_PY_SWIEX_CLSNAME[] = "switch_info_t";
static const char S_PY_OP_T_CLSNAME[] = "op_t";
static const char S_PROPS[] = "props";
static const char S_NAME[] = "name";
static const char S_TITLE[] = "title";
static const char S_COLS[] = "cols";
static const char S_ASM_KEYWORD[] = "asm_keyword";
static const char S_MENU_NAME[] = "menu_name";
static const char S_HOTKEY[] = "hotkey";
static const char S_EMBEDDED[] = "embedded";
static const char S_POPUP_NAMES[] = "popup_names";
static const char S_FLAGS[] = "flags";
static const char S_VALUE_SIZE[] = "value_size";
static const char S_MAY_CREATE_AT[] = "may_create_at";
static const char S_CALC_ITEM_SIZE[] = "calc_item_size";
static const char S_ID[] = "id";
static const char S_PRINTF[] = "printf";
static const char S_TEXT_WIDTH[] = "text_width";
static const char S_SCAN[] = "scan";
static const char S_ANALYZE[] = "analyze";
static const char S_CBSIZE[] = "cbsize";
static const char S_ON_CLICK[] = "OnClick";
static const char S_ON_CLOSE[] = "OnClose";
static const char S_ON_DBL_CLICK[] = "OnDblClick";
static const char S_ON_CURSOR_POS_CHANGED[] = "OnCursorPosChanged";
static const char S_ON_KEYDOWN[] = "OnKeydown";
static const char S_ON_COMPLETE_LINE[] = "OnCompleteLine";
static const char S_ON_FIND_COMPLETIONS[] = "OnFindCompletions";
static const char S_ON_CREATE[] = "OnCreate";
static const char S_ON_POPUP[] = "OnPopup";
static const char S_ON_HINT[] = "OnHint";
static const char S_ON_EDGE_HINT[] = "OnEdgeHint";
static const char S_ON_POPUP_MENU[] = "OnPopupMenu";
static const char S_ON_EDIT_LINE[] = "OnEditLine";
static const char S_ON_INSERT_LINE[] = "OnInsertLine";
static const char S_ON_GET_LINE[] = "OnGetLine";
static const char S_ON_DELETE_LINE[] = "OnDeleteLine";
static const char S_ON_REFRESH[] = "OnRefresh";
static const char S_ON_EXECUTE_LINE[] = "OnExecuteLine";
static const char S_ON_SELECT_LINE[] = "OnSelectLine";
static const char S_ON_SELECTION_CHANGE[] = "OnSelectionChange";
static const char S_ON_GET_ICON[] = "OnGetIcon";
static const char S_ON_GET_LINE_ATTR[] = "OnGetLineAttr";
static const char S_ON_GET_SIZE[] = "OnGetSize";
static const char S_ON_GETTEXT[] = "OnGetText";
static const char S_ON_ACTIVATE[] = "OnActivate";
static const char S_ON_DEACTIVATE[] = "OnDeactivate";
static const char S_ON_SELECT[] = "OnSelect";
static const char S_ON_CREATING_GROUP[] = "OnCreatingGroup";
static const char S_ON_DELETING_GROUP[] = "OnDeletingGroup";
static const char S_ON_GROUP_VISIBILITY[] = "OnGroupVisibility";
static const char S_ON_INIT[] = "OnInit";
static const char S_M_EDGES[] = "_edges";
static const char S_M_NODES[] = "_nodes";
static const char S_M_THIS[] = "_this";
static const char S_M_TITLE[] = "_title";
static const char S_CLINK_NAME[] = "__clink__";
static const char S_ON_VIEW_MOUSE_MOVED[] = "OnViewMouseMoved";
static const char S_MAIN[] = "__main__";
#define VALID_CAPSULE_NAME "$valid$"
#define INVALID_CAPSULE_NAME "$INvalid$"
#ifdef __PYWRAPS__
static const char S_PY_IDA_IDAAPI_MODNAME[] = "__main__";
#else
static const char S_PY_IDA_IDAAPI_MODNAME[] = S_IDA_IDAAPI_MODNAME;
#endif
//------------------------------------------------------------------------
// PyIdc conversion object IDs
#define PY_ICID_INT64 0
#define PY_ICID_BYREF 1
#define PY_ICID_OPAQUE 2
//------------------------------------------------------------------------
// Constants used by the pyvar_to_idcvar and idcvar_to_pyvar functions
#define CIP_FAILED -1 // Conversion error
#define CIP_IMMUTABLE 0 // Immutable object passed. Will not update the object but no error occurred
#define CIP_OK 1 // Success
#define CIP_OK_OPAQUE 2 // Success, but the data pointed to by the PyObject* is an opaque object.
//---------------------------------------------------------------------------
class gil_lock_t
{
private:
PyGILState_STATE state;
public:
gil_lock_t()
{
state = PyGILState_Ensure();
}
~gil_lock_t()
{
PyGILState_Release(state);
}
};
// Declare a variable to acquire/release the GIL
#define PYW_GIL_GET gil_lock_t lock;
// Let's declare just the relevant bits, in order to not have to force
// including 'kernwin.hpp' in all files
#ifndef __KERNWIN_HPP
idaman uint32 ida_export_data debug;
#define IDA_DEBUG_PLUGIN 0x00000020
THREAD_SAFE AS_PRINTF(1, 2) inline int msg(const char *format, ...);
#endif // __KERNWIN_HPP
#ifdef PY3
# ifdef Py_LIMITED_API
# define GIL_CHKCONDFAIL (false)
# else
# define GIL_CHKCONDFAIL (((debug & IDA_DEBUG_PLUGIN) != 0) && !PyGILState_Check())
# endif
#else
# define GIL_CHKCONDFAIL (((debug & IDA_DEBUG_PLUGIN) != 0) \
&& PyGILState_GetThisThreadState() != _PyThreadState_Current)
#endif
#include "idapy.hpp"
#define PYW_GIL_CHECK_LOCKED_SCOPE() \
do \
{ \
if ( GIL_CHKCONDFAIL ) \
{ \
msg("*** WARNING: Code at %s:%d should have the GIL, but apparently doesn't ***\n", \
__FILE__, __LINE__); \
if ( under_debugger ) \
BPT; \
} \
} while ( false )
//-------------------------------------------------------------------------
struct exc_report_t
{
~exc_report_t()
{
if ( PyErr_Occurred() )
PyErr_Print();
}
};
#define PYW_GIL_GET_AND_REPORT_ERROR PYW_GIL_GET; exc_report_t exc;
// Returns the linked object (void *) from a PyObject
idaman void * ida_export pyobj_get_clink(PyObject *pyobj);
//-------------------------------------------------------------------------
// The base for a reference. Will automatically increase the reference
// counter for the object when it is assigned from another ref_t,
// and decrease the reference counter when destroyed.
// This is meant to be used whenever possible, in order to prevent
// situations where, e.g., a given code path is taken and we return from
// a function without first decreasing the reference counter.
//
// Note: You should never, ever have to Py_[INCREF|DECREF] the 'o' object yourself.
// Note: These simple ref_t cannot be created with a PyObject* directly
// (that would be the role of 'newref_t'/'borref_t' below.)
// In other words: simple 'ref_t' instances are never created from the
// result of calling the CPython API. They are only used when in
// idapython land.
// In yet other words: the CPython API only deals in terms of
// 'New references' and 'Borrowed references'. Those are implemented,
// respectively, by the 'newref_t' and 'borref_t' classes below.
// This 'ref_t' is only used for internal handling.
struct ref_t
{
PyObject *o;
ref_t() : o(NULL) {}
ref_t(const ref_t &other) : o(other.o) { incref(); }
~ref_t() { decref(); }
ref_t &operator=(const ref_t &other)
{
// We *must* first (possibly) set & incref the other object,
// because decref() might call the Python's deallocator, which
// might have side-effects, that might affect this ref_t
// instance.
// If that's too many 'might' to your taste, let me illustrate.
//
// py_plgform.hpp's 'plgform_t' holds a 'ref_t' instance, named 'py_obj'.
// If the actual, Qt widget wrapped by that plgform_t gets destroyed,
// plgform_t::unhook() will be called, which will assign an
// empty ref_t instance to its 'py_obj'.
// That will decrement the refcount, and might call the deallocator:
// the plgform_t::destroy static function.
// That function will 'delete' the plgform_t object.
// But, in the ~plgform_t() destructor, the 'py_obj' object will be
// destroyed too: decreasing once again the refcnt (which now falls to -1).
// At this point, all hell breaks loose (or is allowed to).
PyObject *was = o;
o = other.o;
incref();
if ( was != NULL )
Py_DECREF(was);
return *this;
}
void incref() const { if ( o != NULL ) Py_INCREF(o); }
void decref() const { if ( o != NULL ) { QASSERT(30469, o->ob_refcnt > 0); Py_DECREF(o); } }
bool operator==(PyObject *other) const { return o == other; }
bool operator!=(PyObject *other) const { return !((*this) == other); }
bool operator==(const ref_t &other) const { return o == other.o; }
bool operator!=(const ref_t &other) const { return !((*this) == other); }
};
//-------------------------------------------------------------------------
// A 'new' reference. Typically used when the CPython implementation returns
// a PyObject* whose refcnt was already increased, and that the caller is
// responsible for releasing.
//
// This implements the 'New reference' idea at http://docs.python.org/2/c-api/intro.html:
// ---
// "When a function passes ownership of a reference on to its caller,
// the caller is said to receive a new reference"
// ---
// E.g., from "PyObject_GetAttrString"'s doc:
// ---
// "Return value: New reference.
// Retrieve an attribute named attr_name from object o[...]"
// ---
struct newref_t : public ref_t
{
newref_t(); // No.
newref_t(const newref_t &other); // No.
newref_t &operator=(const newref_t &other); // No.
newref_t(PyObject *_o)
{
#ifdef _DEBUG
QASSERT(30409, _o == NULL || _o->ob_refcnt >= 1);
#endif
o = _o;
}
};
//-------------------------------------------------------------------------
// A 'borrowed' reference. Typically used when the CPython implementation returns
// a PyObject* whose ownership is _not_ transferred to the caller.
// Therefore, and since the caller wants to make sure the object is not
// released while it is using it, it must first increase the reference count,
// and then decrease it.
//
// This is similar to the simpler 'ref_t' in that it first increases, and then
// decreases the reference count. The difference is that 'borref_t' instances
// can be created with a PyObject*, while 'ref_t' instances cannot (by design).
//
// This implements the 'Borrowed reference' idea at http://docs.python.org/2/c-api/intro.html:
// ---
// "When no ownership is transferred, the caller is said to borrow the reference.
// Nothing needs to be done for a borrowed reference."
// ---
struct borref_t : public ref_t
{
borref_t(); // No.
borref_t(const newref_t &other); // No.
borref_t &operator=(const newref_t &other); // No.
borref_t(PyObject *_o)
{
o = _o;
incref(); // ~ref_t() will decref(), so we need to incref.
}
};
//------------------------------------------------------------------------
// Vector of ref_t
struct ref_vec_t : public qvector<ref_t>
{
void to_pyobject_pointers(qvector<PyObject*> *out)
{
size_t _n = size();
out->resize(_n);
for ( size_t i = 0; i < _n; ++i )
out->at(i) = at(i).o;
}
};
#ifdef _MSC_VER
// warning C4190: 'PyW_TryImportModule' has C-linkage specified, but returns UDT 'ref_t' which is incompatible with C
#pragma warning(disable : 4190)
#elif defined(__MAC__)
GCC_DIAG_OFF(return-type-c-linkage);
#endif
// Tries to import a module and swallows the exception if it fails and returns NULL
// Return value: New reference.
idaman ref_t ida_export PyW_TryImportModule(const char *name);
// Tries to get an attribute and swallows the exception if it fails and returns NULL
idaman ref_t ida_export PyW_TryGetAttrString(PyObject *py_var, const char *attr);
// Converts a Python number (LONGLONG or normal integer) to an IDC variable (VT_LONG or VT_INT64)
idaman bool ida_export PyW_GetNumberAsIDC(PyObject *py_var, idc_value_t *idc_var);
// Returns a qstring from a Python attribute string
idaman bool ida_export PyW_GetStringAttr(
PyObject *py_obj,
const char *attr_name,
qstring *str);
// Deprecated. Please use specific functions instead.
idaman bool ida_export PyW_GetNumber(PyObject *py_var, uint64 *num, bool *is_64 = NULL);
// Checks if an Python object can be treated like a sequence
idaman bool ida_export PyW_IsSequenceType(PyObject *obj);
// Returns an error string from the last exception (and clears it)
idaman bool ida_export PyW_GetError(qstring *out = NULL, bool clear_err = true);
// If an error occurred (it calls PyGetError) it displays it and return TRUE
// This function is used when calling callbacks
idaman bool ida_export PyW_ShowCbErr(const char *cb_name);
// Utility function to create linked class instances
idaman ref_t ida_export create_linked_class_instance(const char *modname, const char *clsname, void *lnk);
// Returns the string representation of a PyObject
idaman bool ida_export PyW_ObjectToString(PyObject *obj, qstring *out);
// Utility function to convert a python object to an IDC object
// and sets a python exception on failure.
idaman bool ida_export pyvar_to_idcvar_or_error(const ref_t &py_obj, idc_value_t *idc_obj);
// Creates and initializes an IDC exception
idaman error_t ida_export PyW_CreateIdcException(idc_value_t *res, const char *msg);
//
// Conversion functions
//
#define PYWCVTF_AS_TUPLE 0x1
#define PYWCVTF_INT64_AS_UNSIGNED_PYLONG 0x2 // don't wrap int64 into 'PyIdc_cvt_int64__' objects, but make them 'long' instead
#define PYWCVTF_STR_AS_BYTES 0x4 // VT_STR objects will be converted into 'bytes', not strings coming from UTF-8 data
// Converts from IDC to Python
idaman bool ida_export pyw_convert_idc_args(
const idc_value_t args[],
int nargs,
ref_vec_t &pargs,
uint32 flags,
qstring *errbuf = NULL);
// Converts from IDC to Python
// We support converting VT_REF IDC variable types
idaman int ida_export idcvar_to_pyvar(
const idc_value_t &idc_var,
ref_t *py_var,
uint32 flags=0);
//-------------------------------------------------------------------------
// Converts Python variable to IDC variable
// gvar_sn is used in case the Python object was a created from a call to idcvar_to_pyvar and the IDC object was a VT_REF
idaman int ida_export pyvar_to_idcvar(
const ref_t &py_var,
idc_value_t *idc_var,
int *gvar_sn=NULL);
//-------------------------------------------------------------------------
// Walks a Python list or Sequence and calls the callback
idaman Py_ssize_t ida_export pyvar_walk_list(
PyObject *py_list,
int (idaapi *cb)(const ref_t &py_item, Py_ssize_t index, void *ud)=NULL,
void *ud = NULL);
// Converts a vector to a Python list object
idaman ref_t ida_export PyW_SizeVecToPyList(const sizevec_t &vec);
idaman ref_t ida_export PyW_UvalVecToPyList(const uvalvec_t &vec);
// Converts a Python list, to a vector of the given type.
// An exception will be raised in case:
// - py_list is not a sequence
// - a member of py_list cannot be converted to the numeric target type
idaman Py_ssize_t ida_export PyW_PyListToSizeVec(sizevec_t *out, PyObject *py_list);
idaman Py_ssize_t ida_export PyW_PyListToEaVec(eavec_t *out, PyObject *py_list);
idaman Py_ssize_t ida_export PyW_PyListToStrVec(qstrvec_t *out, PyObject *py_list);
#ifndef LUMINA_HPP // I'd rather put the def of ea64_t and ea64vec_t into pro.h...
#ifdef __EA64__
typedef ea_t ea64_t;
#else
typedef uint64 ea64_t;
#endif
typedef qvector<ea64_t> ea64vec_t;
#endif // LUMINA_HPP
idaman Py_ssize_t ida_export PyW_PyListToEa64Vec(ea64vec_t *out, PyObject *py_list);
//-------------------------------------------------------------------------
#include <idd.hpp>
idaman PyObject *ida_export meminfo_vec_t_to_py(meminfo_vec_t &ranges);
//-------------------------------------------------------------------------
idaman void ida_export PyW_register_compiled_form(PyObject *py_form);
//-------------------------------------------------------------------------
idaman void ida_export PyW_unregister_compiled_form(PyObject *py_form);
// #define PYGDBG_ENABLED
#ifdef PYGDBG_ENABLED
#define PYGLOG(...) msg(__VA_ARGS__)
#else
#define PYGLOG(...)
#endif
//-------------------------------------------------------------------------
struct pycall_res_t
{
pycall_res_t(PyObject *pyo)
: result(pyo)
{
PYGLOG("return code: %p\n", result.o);
}
~pycall_res_t()
{
if ( PyErr_Occurred() )
PyErr_Print();
}
inline bool success() const { return result.o != NULL; }
newref_t result;
private:
pycall_res_t(); // No.
};
#include <loader.hpp>
//-------------------------------------------------------------------------
// CustomIDAMemo wrappers
//-------------------------------------------------------------------------i
class lookup_info_t;
class py_customidamemo_t;
struct lookup_entry_t
{
lookup_entry_t() : view(NULL), py_view(NULL) {}
TWidget *view;
py_customidamemo_t *py_view;
};
DECLARE_TYPE_AS_MOVABLE(lookup_entry_t);
typedef qvector<lookup_entry_t> lookup_entries_t;
#include <graph.hpp>
#define PY_LINFO_HLPPRM_new_entry (lookup_info_t *_this, py_customidamemo_t *py_view)
#define PY_LINFO_PARAMS_new_entry (py_customidamemo_t *py_view)
#define PY_LINFO_TRANSM_new_entry (this, py_view)
#define PY_LINFO_HLPPRM_commit (lookup_info_t *_this, lookup_entry_t &e, TWidget *view)
#define PY_LINFO_PARAMS_commit (lookup_entry_t &e, TWidget *view)
#define PY_LINFO_TRANSM_commit (this, e, view)
#define PY_LINFO_HLPPRM_find_by_view (const lookup_info_t *_this, py_customidamemo_t **out_py_view, const TWidget *view)
#define PY_LINFO_PARAMS_find_by_view (py_customidamemo_t **out_py_view, const TWidget *view) const
#define PY_LINFO_TRANSM_find_by_view (this, out_py_view, view)
#define PY_LINFO_HLPPRM_find_by_py_view (const lookup_info_t *_this, TWidget **out_view, const py_customidamemo_t *py_view)
#define PY_LINFO_PARAMS_find_by_py_view (TWidget **out_view, const py_customidamemo_t *py_view) const
#define PY_LINFO_TRANSM_find_by_py_view (this, out_view, py_view)
#define PY_LINFO_HLPPRM_del_by_py_view (lookup_info_t *_this, const py_customidamemo_t *py_view)
#define PY_LINFO_PARAMS_del_by_py_view (const py_customidamemo_t *py_view)
#define PY_LINFO_TRANSM_del_by_py_view (this, py_view)
#define DECL_LINFO_HELPER(decl, RType, MName, MParams) \
decl RType ida_export lookup_info_t_##MName MParams
#define DECL_LINFO_HELPERS(decl) \
DECL_LINFO_HELPER(decl, lookup_entry_t&, new_entry, PY_LINFO_HLPPRM_new_entry); \
DECL_LINFO_HELPER(decl, void, commit, PY_LINFO_HLPPRM_commit); \
DECL_LINFO_HELPER(decl, bool, find_by_view, PY_LINFO_HLPPRM_find_by_view);\
DECL_LINFO_HELPER(decl, bool, find_by_py_view, PY_LINFO_HLPPRM_find_by_py_view);\
DECL_LINFO_HELPER(decl, bool, del_by_py_view, PY_LINFO_HLPPRM_del_by_py_view);
DECL_LINFO_HELPERS(idaman);
class py_customidamemo_t;
class lookup_info_t
{
DECL_LINFO_HELPERS(friend);
public:
#define PY_LINFO_TRAMPOLINE(RType, MName, MParams, PNames) \
RType MName MParams { return lookup_info_t_##MName PNames; }
PY_LINFO_TRAMPOLINE(lookup_entry_t&, new_entry, PY_LINFO_PARAMS_new_entry, PY_LINFO_TRANSM_new_entry);
PY_LINFO_TRAMPOLINE(void, commit, PY_LINFO_PARAMS_commit, PY_LINFO_TRANSM_commit);
PY_LINFO_TRAMPOLINE(bool, find_by_view, PY_LINFO_PARAMS_find_by_view, PY_LINFO_TRANSM_find_by_view);
PY_LINFO_TRAMPOLINE(bool, find_by_py_view, PY_LINFO_PARAMS_find_by_py_view, PY_LINFO_TRANSM_find_by_py_view);
PY_LINFO_TRAMPOLINE(bool, del_by_py_view, PY_LINFO_PARAMS_del_by_py_view, PY_LINFO_TRANSM_del_by_py_view);
#undef PY_LINFO_TRAMPOLINE
private:
lookup_entries_t entries;
};
#ifdef __NT__
#ifdef PLUGIN_SUBMODULE
#define plugin_export_data __declspec(dllimport)
#else
#define plugin_export_data __declspec(dllexport)
#endif
#else // unix
#define plugin_export_data __attribute__((visibility("default")))
#endif
extern lookup_info_t plugin_export_data pycim_lookup_info;
//-------------------------------------------------------------------------
struct pycim_callback_id_t
{
qstring name;
int have;
};
struct pycim_callbacks_ids_t : public qvector<pycim_callback_id_t>
{
void add(const char *_n, int _h)
{
pycim_callback_id_t &o = push_back();
o.name = _n;
o.have = _h;
}
};
//-------------------------------------------------------------------------
//
//-------------------------------------------------------------------------
#define PY_CIM_HLPPRM_create_groups (py_customidamemo_t *_this, PyObject *groups_infos)
#define PY_CIM_PARAMS_create_groups (PyObject *groups_infos)
#define PY_CIM_TRANSM_create_groups (this, groups_infos)
#define PY_CIM_HLPPRM_delete_groups (py_customidamemo_t *_this, PyObject *groups, PyObject *new_current)
#define PY_CIM_PARAMS_delete_groups (PyObject *groups, PyObject *new_current)
#define PY_CIM_TRANSM_delete_groups (this, groups, new_current)
#define PY_CIM_HLPPRM_set_groups_visibility (py_customidamemo_t *_this, PyObject *groups, PyObject *expand, PyObject *new_current)
#define PY_CIM_PARAMS_set_groups_visibility (PyObject *groups, PyObject *expand, PyObject *new_current)
#define PY_CIM_TRANSM_set_groups_visibility (this, groups, expand, new_current)
#define PY_CIM_HLPPRM_collect_pyobject_callbacks (py_customidamemo_t *_this, PyObject *self)
#define PY_CIM_PARAMS_collect_pyobject_callbacks (PyObject *in_self)
#define PY_CIM_TRANSM_collect_pyobject_callbacks (this, in_self)
#define PY_CIM_HLPPRM_collect_class_callbacks_ids (py_customidamemo_t *_this, pycim_callbacks_ids_t *out)
#define PY_CIM_PARAMS_collect_class_callbacks_ids (pycim_callbacks_ids_t *out)
#define PY_CIM_TRANSM_collect_class_callbacks_ids (this, out)
#define PY_CIM_HLPPRM_bind (py_customidamemo_t *_this, PyObject *self, TWidget *view)
#define PY_CIM_PARAMS_bind (PyObject *in_self, TWidget *in_view)
#define PY_CIM_TRANSM_bind (this, in_self, in_view)
#define PY_CIM_HLPPRM_unbind (py_customidamemo_t *_this, bool clear_view)
#define PY_CIM_PARAMS_unbind (bool clear_view)
#define PY_CIM_TRANSM_unbind (this, clear_view)
#define DECL_CIM_HELPER(decl, RType, MName, MParams) \
decl RType ida_export py_customidamemo_t_##MName MParams
#define DECL_CIM_HELPERS(decl) \
DECL_CIM_HELPER(decl, PyObject*, create_groups, PY_CIM_HLPPRM_create_groups); \
DECL_CIM_HELPER(decl, PyObject*, delete_groups, PY_CIM_HLPPRM_delete_groups); \
DECL_CIM_HELPER(decl, PyObject*, set_groups_visibility, PY_CIM_HLPPRM_set_groups_visibility);\
\
DECL_CIM_HELPER(decl, bool, collect_pyobject_callbacks, PY_CIM_HLPPRM_collect_pyobject_callbacks); \
DECL_CIM_HELPER(decl, void, collect_class_callbacks_ids, PY_CIM_HLPPRM_collect_class_callbacks_ids); \
DECL_CIM_HELPER(decl, bool, bind, PY_CIM_HLPPRM_bind); \
DECL_CIM_HELPER(decl, void, unbind, PY_CIM_HLPPRM_unbind); \
DECL_CIM_HELPERS(idaman);
//-------------------------------------------------------------------------
#define PY_CIM_TRAMPOLINE(RType, MName, MParams, PNames) \
RType MName MParams { return py_customidamemo_t_##MName PNames; }
class py_customidamemo_t
{
// can use up to 16 bits; not more! (GRCODE_HAVE_* uses the rest)
enum
{
GRBASE_HAVE_VIEW_MOUSE_MOVED = 0x0001,
};
int cb_flags;
// View events
void on_view_mouse_moved(const view_mouse_event_t *event);
// View events that are bound with 'set_custom_viewer_handler()'.
static void idaapi s_on_view_mouse_moved(
TWidget *cv,
int shift,
view_mouse_event_t *e,
void *ud);
DECL_CIM_HELPERS(friend);
protected:
ref_t self;
TWidget *view;
pycim_callbacks_ids_t cbids;
PY_CIM_TRAMPOLINE(bool, collect_pyobject_callbacks, PY_CIM_PARAMS_collect_pyobject_callbacks, PY_CIM_TRANSM_collect_pyobject_callbacks);
PY_CIM_TRAMPOLINE(virtual void, collect_class_callbacks_ids, PY_CIM_PARAMS_collect_class_callbacks_ids, PY_CIM_TRANSM_collect_class_callbacks_ids);
PY_CIM_TRAMPOLINE(bool, bind, PY_CIM_PARAMS_bind, PY_CIM_TRANSM_bind);
PY_CIM_TRAMPOLINE(void, unbind, PY_CIM_PARAMS_unbind, PY_CIM_TRANSM_unbind);
friend TWidget *pycim_get_widget(PyObject *self);
public:
py_customidamemo_t()
: cb_flags(0),
self(newref_t(NULL)),
view(NULL)
{
PYGLOG("%p: py_customidamemo_t()\n", this);
}
virtual ~py_customidamemo_t()
{
PYGLOG("%p: ~py_customidamemo_t()\n", this);
unbind(true);
pycim_lookup_info.del_by_py_view(this);
}
virtual void refresh()
{
refresh_viewer(view);
}
inline bool has_callback(int flag) { return (cb_flags & flag) != 0; }
PY_CIM_TRAMPOLINE(PyObject*, create_groups, PY_CIM_PARAMS_create_groups, PY_CIM_TRANSM_create_groups);
PY_CIM_TRAMPOLINE(PyObject*, delete_groups, PY_CIM_PARAMS_delete_groups, PY_CIM_TRANSM_delete_groups);
PY_CIM_TRAMPOLINE(PyObject*, set_groups_visibility, PY_CIM_PARAMS_set_groups_visibility, PY_CIM_TRANSM_set_groups_visibility);
};
#undef PY_CIM_TRAMPOLINE
#undef DECL_CIM_HELPERS
#undef DECL_CIM_HELPER
//-------------------------------------------------------------------------
inline void *view_extract_this(PyObject *self)
{
PYW_GIL_CHECK_LOCKED_SCOPE();
ref_t py_this(PyW_TryGetAttrString(self, S_M_THIS));
if ( py_this == NULL || !PyCapsule_IsValid(py_this.o, VALID_CAPSULE_NAME) )
return NULL;
return PyCapsule_GetPointer(py_this.o, VALID_CAPSULE_NAME);
}
//-------------------------------------------------------------------------
//
//-------------------------------------------------------------------------
#include <typeinf.hpp>
#define DECL_REG_UNREG_REFCOUNTED(Type) \
idaman void ida_export til_register_python_##Type##_instance(Type *inst); \
idaman void ida_export til_deregister_python_##Type##_instance(Type *inst);
DECL_REG_UNREG_REFCOUNTED(tinfo_t);
DECL_REG_UNREG_REFCOUNTED(ptr_type_data_t);
DECL_REG_UNREG_REFCOUNTED(array_type_data_t);
DECL_REG_UNREG_REFCOUNTED(func_type_data_t);
DECL_REG_UNREG_REFCOUNTED(udt_type_data_t);
#undef DECL_REG_UNREG_REFCOUNTED
//-------------------------------------------------------------------------
// Context structure used by register/unregister timer
struct py_timer_ctx_t
{
py_timer_ctx_t() : timer_id(NULL) {}
qtimer_t timer_id;
ref_t pyfunc;
};
//-------------------------------------------------------------------------
idaman py_timer_ctx_t *ida_export python_timer_new(PyObject *py_callback);
idaman void ida_export python_timer_del(py_timer_ctx_t *t);
//-------------------------------------------------------------------------
idaman ref_t ida_export try_create_swig_wrapper(ref_t mod, const char *clsname, void *cobj);
//-------------------------------------------------------------------------
idaman ssize_t ida_export get_callable_arg_count(ref_t callable);
//-------------------------------------------------------------------------
// Useful for small operations that must not be interrupted: e.g., when
// wrapping an insn_t into a SWiG proxy object, or when destroying
// such an instance from the kernel. Use 'uninterruptible_op_t' if you can.
idaman void ida_export set_interruptible_state(bool interruptible);
struct uninterruptible_op_t
{
uninterruptible_op_t() { set_interruptible_state(false); }
~uninterruptible_op_t() { set_interruptible_state(true); }
};
//-------------------------------------------------------------------------
struct new_execution_t;
idaman void ida_export setup_new_execution(new_execution_t *instance, bool setup);
struct new_execution_t
{
bool created;
new_execution_t() { setup_new_execution(this, true); }
~new_execution_t() { setup_new_execution(this, false); }
};
//-------------------------------------------------------------------------
idaman bool ida_export is_api695_compat_enabled();
//-------------------------------------------------------------------------
idaman bool ida_export idapython_hook_to_notification_point(
hook_type_t hook_type,
hook_cb_t *cb,
void *user_data,
bool is_hooks_base);
idaman bool ida_export idapython_unhook_from_notification_point(
hook_type_t hook_type,
hook_cb_t *cb,
void *user_data);
#define hook_to_notification_point USE_IDAPYTHON_HOOK_TO_NOTIFICATION_POINT
#define unhook_from_notification_point USE_IDAPYTHON_UNHOOK_FROM_NOTIFICATION_POINT
//-------------------------------------------------------------------------
#define HBF_CALL_WITH_NEW_EXEC 0x00000001
#define HBF_VOLATILE_METHOD_SET 0x00000002
struct hooks_base_t
{
const char *class_name;
qstring identifier;
hook_cb_t *cb;
hook_type_t type;
uint32 flags;
typedef std::map<int,uchar> has_nondef_map_t;
has_nondef_map_t has_nondef;
bool hook() { return cb != NULL ? idapython_hook_to_notification_point(type, cb, this, true) : false; }
bool unhook() { return cb != NULL ? idapython_unhook_from_notification_point(type, cb, this) : false; }
bool call_requires_new_execution() const { return (flags & HBF_CALL_WITH_NEW_EXEC) != 0; }
bool has_fixed_method_set() const { return (flags & HBF_VOLATILE_METHOD_SET) == 0; }
hooks_base_t(
const char *_class_name,
hook_cb_t *_cb,
hook_type_t _type,
uint32 _flags=0)
: class_name(_class_name),
cb(_cb),
type(_type),
flags(_flags) {}
virtual ~hooks_base_t() { unhook(); }
struct ida_local event_code_to_method_name_t
{
int code;
const char *method_name;
};
protected:
void init_director_hooks(
PyObject *self,
const event_code_to_method_name_t *mappings,
size_t count)
{
// identifier
{
ref_t py_id = newref_t(PyObject_GetAttrString(self, "id"));
if ( py_id == NULL || !IDAPyStr_Check(py_id.o) )
py_id = newref_t(PyObject_Repr(self));
if ( py_id != NULL && IDAPyStr_Check(py_id.o) )
IDAPyStr_AsUTF8(&identifier, py_id.o);
}
// method set
QASSERT(30588, has_fixed_method_set());
qstring buf(class_name);
QASSERT(30589, !buf.empty());
char *p = qstrchr(buf.begin(), '.');
QASSERT(30590, p != NULL);
*p++ = '\0';
newref_t py_mod(PyImport_ImportModule(buf.c_str()));
#ifdef TESTABLE_BUILD
QASSERT(30591, py_mod != NULL);
#endif
if ( py_mod != NULL )
{
newref_t py_def_class(PyObject_GetAttrString(py_mod.o, p));
newref_t py_this_class(PyObject_GetAttrString(self, "__class__"));
#ifdef TESTABLE_BUILD
QASSERT(30592, py_def_class != NULL && py_this_class != NULL);
#endif
if ( py_def_class != NULL && py_this_class != NULL )
{
for ( size_t i = 0; i < count; ++i )
{
const event_code_to_method_name_t &cur = mappings[i];
uchar _has_nondef = 0;
newref_t py_def_meth(PyObject_GetAttrString(py_def_class.o, cur.method_name));
newref_t py_this_meth(PyObject_GetAttrString(py_this_class.o, cur.method_name));
#ifdef TESTABLE_BUILD
QASSERT(30593, py_def_meth != NULL && py_this_meth != NULL);
#endif
if ( py_def_meth != NULL && py_this_meth != NULL )
{
#ifdef BC695
if ( PyObject_HasAttrString(py_def_meth.o, "bc695_trampoline") > 0 )
_has_nondef = 2;
else
#endif
#ifdef PY3
_has_nondef = PyObject_RichCompareBool(py_this_meth.o, py_def_meth.o, Py_EQ) == 0 ? 1 : 0;
#else
_has_nondef = PyObject_Compare(py_this_meth.o, py_def_meth.o) != 0 ? 1 : 0;
#endif
}
has_nondef[cur.code] = _has_nondef;
}
}
}
}
void ensure_no_method_when_no_695_compat(
PyObject *self,
const char *forbidden_method_name,
const char *replacement_method_name)
{
if ( !is_api695_compat_enabled() )
{
if ( PyObject_HasAttrString(self, "__class__") )
{
newref_t py_this_class(PyObject_GetAttrString(self, "__class__"));
if ( py_this_class != NULL
&& PyObject_HasAttrString(py_this_class.o, forbidden_method_name) )
{
msg("WARNING: The method \"%s::%s\" won't be called (it has been replaced with \"%s::%s\")\n",
class_name, forbidden_method_name, class_name, replacement_method_name);
}
}
}
}
qstring dump_state(
const event_code_to_method_name_t *mappings,
size_t mappings_size) const
{
qstring buf;
#ifdef TESTABLE_BUILD
buf.sprnt("%s(this=%p) \"%s\" {type=%d, cb=%p, flags=%x}",
class_name, this, identifier.c_str(), int(type), cb, flags);
if ( has_fixed_method_set() )
{
for ( size_t i = 0; i < mappings_size; ++i )
{
const hooks_base_t::event_code_to_method_name_t &m = mappings[i];
has_nondef_map_t::const_iterator it = has_nondef.find(m.code);
if ( it != has_nondef.end() && it->second > 0 )
buf.cat_sprnt("\n\treimplements \"%s\"%s",
m.method_name,
it->second > 1 ? " (as 6.95 bw-compat)" : "");
}
}
else
{
buf.append(" is fully dynamic, and won't use 'has_nondef' lookup");
QASSERT(30594, has_nondef.empty());
}
if ( buf.last() != '\n' )
buf.append('\n');
#else
qnotused(mappings);
qnotused(mappings_size);
#endif
return buf;
}
};
//-------------------------------------------------------------------------
idaman THREAD_SAFE void ida_export idapython_show_wait_box(
bool internal,
const char *message);
idaman void ida_export idapython_hide_wait_box();
#define show_wait_box USE_IDAPYTHON_SHOW_WAIT_BOX
#define hide_wait_box USE_IDAPYTHON_HIDE_WAIT_BOX
//-------------------------------------------------------------------------
idaman bool ida_export idapython_convert_cli_completions(
qstrvec_t *out_completions,
int *out_match_start,
int *out_match_end,
ref_t py_res);
//-------------------------------------------------------------------------
idaman int ida_export pylong_to_byte_array(
bytevec_t *out_allocated_buffer,
PyObject *in,
bool little_endian=true,
bool is_signed=true);
//-------------------------------------------------------------------------
struct module_callbacks_t
{
module_callbacks_t() { memset(this, 0, sizeof(*this)); }
void (*init) (void);
void (*term) (void);
void (*closebase) (void);
};
DECLARE_TYPE_AS_MOVABLE(module_callbacks_t);
idaman void register_module_lifecycle_callbacks(
const module_callbacks_t &cbs);
idaman void ida_export prepare_programmatic_plugin_load(const char *path);
#endif // __PYWRAPS_HPP__