summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTreeki <treeki@gmail.com>2012-01-08 01:16:35 +0100
committerTreeki <treeki@gmail.com>2012-01-08 01:16:35 +0100
commit96816165206050b35dd63c5a873527ee2c773326 (patch)
treeae53174dc2916aa8c4026394ed852d1404d34468
parentca9d90bd1db97737893690d370e4f21e0c3955e8 (diff)
downloadclassy-master.tar.gz
classy-master.zip
pure virtual support addedHEADmaster
-rw-r--r--README5
-rw-r--r--classy.py63
2 files changed, 47 insertions, 21 deletions
diff --git a/README b/README
index beb901f..772f6cb 100644
--- a/README
+++ b/README
@@ -38,6 +38,7 @@ Supported so far:
- Overrides are shown at the top of the original method body
- Renames and argument list changes are propagated from original methods
to overrides (Though not vice versa yet)
+ - Pure virtuals are supported
That's all for now, I think...
@@ -51,8 +52,6 @@ Current Todo:
- Named arguments to methods
- Return types for methods
- Const methods
-- Improve vtable end detection heuristics
-- Support pure virtuals.
- Handle IDA chooser history/defaults correctly everywhere
- Better keybindings
- Rename class menu item
@@ -70,7 +69,7 @@ Caveats:
- Probably won't work as well with non-CodeWarrior stuff.
Notes:
-- When autocreating virtual methods, start with the base class!!
+- When creating virtual methods, start with the base class!!
Otherwise, you might end up defining an override as a virtual
method. And that would be bad.
diff --git a/classy.py b/classy.py
index 6d23b7b..1af146a 100644
--- a/classy.py
+++ b/classy.py
@@ -194,7 +194,9 @@ class Class(object):
def find_vtable_end(self):
check = self.vtable + 4
- while Dword(check + 4) != 0:
+ while True:
+ value = Dword(check + 4)
+ if value < 0x80000000 or value > 0x817FFFFF: break
check += 4
print('Inferred vtable as %08x .. %08x' % (self.vtable, check))
@@ -307,6 +309,7 @@ class Method(object):
def is_null(self): return False
def is_virtual(self): return False
+ def has_code(self): return True
def rename(self, name):
self.name = name
@@ -315,22 +318,23 @@ class Method(object):
def refresh(self):
MakeName(self.ea, "%s__%s%s" % (self.name, self.owner.mangled_name, self.mangled_args))
- # figure out if any virtual xrefs include us
- # a bit slow, but who cares
- call_dict = db.virtual_calls
- func = idaapi.get_func(self.ea)
- check = func.startEA
- end = func.endEA
+ if self.has_code():
+ # figure out if any virtual xrefs include us
+ # a bit slow, but who cares
+ call_dict = db.virtual_calls
+ func = idaapi.get_func(self.ea)
+ check = func.startEA
+ end = func.endEA
- done_already = {}
+ done_already = {}
- while check <= end:
- if check in call_dict:
- method = call_dict[check]
- if method not in done_already:
- method.refresh_comment()
- done_already[method] = True
- check += 4
+ while check <= end:
+ if check in call_dict:
+ method = call_dict[check]
+ if method not in done_already:
+ method.refresh_comment()
+ done_already[method] = True
+ check += 4
def unlink(self, orphan=False):
if self.name == '__ct':
@@ -437,13 +441,20 @@ class VirtualMethod(Method):
SetFunctionCmt(self.ea, self.get_comment(), 0)
+class PureVirtualMethod(VirtualMethod):
+ def has_code(self): return False
+
+ def __init__(self, owner, name, vt_offset):
+ VirtualMethod.__init__(self, owner, name, owner.vtable+vt_offset, vt_offset)
+
+ def refresh_comment(self):
+ MakeComm(self.ea, self.get_comment())
+
+
class OverrideMethod(VirtualMethod):
def __init__(self, owner, name, ea, vt_offset, base):
VirtualMethod.__init__(self, owner, name, ea, vt_offset)
- if ea == BADADDR || ea == 0:
- raise ValueError("An override method can't be pure!!")
-
self.base = base
self.original = (hasattr(base, 'original') and base.original) or base
self.copy_signature(self.original)
@@ -547,6 +558,10 @@ def get_current_function():
func = idaapi.get_func(Dword(ea))
if func is None:
+ # otherwise, might be entered into the method DB (as a pure virtual?)
+ if ea in db.known_methods:
+ return ea
+
# and if it's still none ...
Warning('Place the cursor on top of a function.')
raise ValueError
@@ -728,7 +743,19 @@ def register_virtual_method():
Warning('This class does not have a virtual table defined.')
return
+ # check for pure virtuals and handle them separately
+ current_ea = idaapi.get_screen_ea()
+ if Dword(current_ea) == 0 and current_ea > cls.vtable and current_ea <= cls.vtable_end:
+ offset = current_ea - cls.vtable
+
+ name = idaapi.askstr(idaapi.HIST_IDENT, 'vf%02X' % offset, 'Enter a name for this pure virtual')
+ method = PureVirtualMethod(cls, name, offset)
+ method.refresh()
+ Refresh()
+ return
+
ea = get_current_function()
+
unlink_method_if_exists(ea)
# try to find it within the vtable