Candidate release of source code.

This commit is contained in:
Dan 2019-03-26 13:45:32 -04:00
parent db81e6b3b0
commit 79d8f164f8
12449 changed files with 2800756 additions and 16 deletions

View file

@ -0,0 +1,175 @@
"""
Ties the Ghidra documentation into the builtin Python help.
"""
import __builtin__
import java
import re
import json
import os
import zipfile
from ghidra.framework import Application
from ghidra.util import SystemUtilities
class _Helper:
def __init__(self):
self.orig_help = __builtin__.help
if SystemUtilities.isInHeadlessMode():
# ./pythonRun scenario
self.msg = "\nExample workflow:\n"
self.msg += " # Import headless analyzer\n"
self.msg += " from ghidra.app.util.headless import HeadlessAnalyzer\n\n"
self.msg += " # View HeadlessAnalyzer API\n"
self.msg += " help(HeadlessAnalyzer)\n\n"
self.msg += " # Get a HeadlessAnalyzer instance\n"
self.msg += " headless = HeadlessAnalyzer.getInstance()\n\n"
self.msg += " # Get headless options\n"
self.msg += " options = headless.getOptions()\n\n"
self.msg += " # View HeadlessOptions API and set options accordingly\n"
self.msg += " help(options)\n\n"
self.msg += " # View processLocal method API\n"
self.msg += " help(headless.processLocal)\n\n"
self.msg += " # Perform headless processing\n"
self.msg += " headless.processLocal(...)\n\n"
else:
# PythonPlugin scenario
self.msg = "Press 'F1' for usage instructions"
def __call__(self, param=None):
def get_class_and_method(param):
if param is None and not SystemUtilities.isInHeadlessMode():
# Enable help() in PythonPlugin scenario to show help for GhidraScript
return "ghidra.app.script.GhidraScript", None
class_name = None
method_name = None
if type(param) in [type(1), type(1j), type(1L), type(1.0), type(None), type(True), type([]), type({}), type(()), type({1})]:
# These are instances of builtin types, so skip
pass
elif type(param) == type(str):
# These are builtin Python types, so skip
pass
elif type(param) == type(str.split):
# These are python functions, so skip
pass
elif type(param) == type(java):
# These are java packages, which we don't don't document, so skip
pass
elif type(param) == type(java.lang.Object):
# This is a java class, so extract its class name
match = re.search("'(.*)'", str(param))
if match is not None:
class_name = match.group(1)
elif type(param) == type(java.lang.Object().toString):
# This is a java method, so extract its class name and method name
tokens = str(param).split(" ")[2].split(".")
class_name = ".".join(tokens[:-1])
method_name = tokens[-1]
else:
# Assuming this is a java object, so extract its class name
match = re.search("'(.*)'", str(type(param)))
if match is not None:
class_name = match.group(1)
return class_name, method_name
def get_jsondoc(class_name):
jsondoc = None
try:
root = Application.getApplicationRootDirectory().getFile(False).getParentFile().getAbsolutePath()
javadoc_zip_name = "GhidraAPI_javadoc.zip"
if SystemUtilities.isInDevelopmentMode():
javadoc_zip = root + "/build/tmp/" + javadoc_zip_name
else:
javadoc_zip = root + "/docs/" + javadoc_zip_name
if os.path.exists(javadoc_zip):
json_path = "api/" + class_name.replace('.', '/') + '.json'
with zipfile.ZipFile(javadoc_zip, "r").open(json_path) as f:
jsondoc = json.load(f)
except (IOError, KeyError) as e:
pass
return jsondoc
def format_class(cls):
sig = "class " + cls["name"] + "\n"
if "extends" in cls:
sig += " extends " + cls["extends"] + "\n"
implements = ""
for interface in cls["implements"]:
if len(implements) > 0:
implements += ", "
implements += interface
if len(implements) > 0:
sig += " implements " + implements + " \n"
sig += "\n" + cls["comment"]
return sig
def format_field(field):
sig = "%s %s" % (field["type_long"], field["name"])
if field["static"]:
sig = "static " + sig
if field["constant_value"]:
sig += " = " + field["constant_value"]
sig += "\n"
desc = " %s\n" % (field["comment"]) if len(field["comment"]) > 0 else ""
return sig + desc
def format_method(method):
paramsig = ""
args = ""
for param in method["params"]:
if len(paramsig) > 0:
paramsig += ", "
paramsig += "%s %s" % (param["type_short"], param["name"])
args += " @param %s (%s): %s\n" % (param["name"], param["type_long"], param["comment"])
throws = ""
for exception in method["throws"]:
throws += " @throws %s: %s\n" % (exception["type_short"], exception["comment"])
sig = "%s %s(%s)\n" % (method["return"]["type_short"], method["name"], paramsig)
if method["static"]:
sig = "static " + sig
desc = " %s\n\n" % (method["comment"]) if len(method["comment"]) > 0 else ""
ret = ""
if method["return"]["type_short"] != "void":
ret = " @return %s: %s\n" % (method["return"]["type_long"], method["return"]["comment"])
return sig + desc + args + ret + throws
class_name, method_name = get_class_and_method(param)
if class_name is None:
self.orig_help(param)
else:
try_again = True
while try_again:
try_again = False
print "Searching API for " + class_name + ("" if method_name is None else "." + method_name + "()") + "..."
jsondoc = get_jsondoc(class_name)
if jsondoc is None:
print "No API found for " + class_name
elif method_name is None:
print "#####################################################"
print format_class(jsondoc)
print "#####################################################\n"
for field in jsondoc["fields"]:
print format_field(field)
print "-----------------------------------------------------"
for method in jsondoc["methods"]:
print format_method(method)
print "-----------------------------------------------------"
else:
found_method = False
for method in jsondoc["methods"]:
if method["name"] == method_name:
print "-----------------------------------------------------"
print format_method(method)
print "-----------------------------------------------------"
found_method = True
if not found_method:
# The method may be inherited, so check for a super class and try again
if "extends" in jsondoc:
class_name = jsondoc["extends"]
try_again = True
def __repr__(self):
return self.msg
__builtin__.help = _Helper()

View file

@ -0,0 +1,526 @@
"""
Provides a variety of introspective-type support functions for
things like call tips and command auto completion.
NOTE: this file is a modification of Patrick O'Brien's version 1.62
"""
from __future__ import nested_scopes
import cStringIO
import inspect
import sys
import tokenize
import types
import __main__
from ghidra.python import PythonCodeCompletionFactory
import java # needed for java.lang.Class
try:
True
except NameError:
True = 1==1
False = 1==0
#from java.lang.System.out import println
def getAutoCompleteList(command='', locals=None, includeMagic=1,
includeSingle=1, includeDouble=1):
"""Return list of auto-completion tuples for command.
First entry is the possible completions, and second entry is the
of actual string that should be added to do the completion.
The list of options will be based on the locals namespace."""
attributes = []
object = None
# Get the proper chunk of code from the command.
#root = getRoot(command, terminator='.')
# and get the part of the completion we should filter on
(root, filter) = getRootAndFilter(command, terminator='.')
if root:
jump_past_period = 1
else:
jump_past_period = 0
#println("root='" + root + "'")
#println("filter='" + filter + "'")
if not root:
# top-level?
attributes = locals
else:
try:
if locals is not None:
object = eval(root, locals)
else:
object = eval(root)
except:
#print "could not eval(", root, "):", sys.exc_info()[0]
pass
else:
attributes = getAttributeNames(object, includeMagic,
includeSingle, includeDouble)
completion_list = []
for attribute in attributes:
if attribute.lower().startswith(filter.lower()):
try:
if object is not None:
pyObj = getattr(object, attribute)
else:
pyObj = locals[attribute]
completion_list.append(PythonCodeCompletionFactory.
newCodeCompletion(attribute,
attribute[len(filter):],
pyObj))
except:
# hmm, problem evaluating? Examples of this include
# inner classes, e.g. access$0, which aren't valid Python
# anyway
pass
completion_list.sort(compare_completions)
return completion_list
def compare_completions(comp1, comp2):
return cmp(comp1.description, comp2.description)
def getAttributeNames(object, includeMagic=1, includeSingle=1,
includeDouble=1):
"""Return list of unique attributes, including inherited, for object."""
attributes = []
dict = {}
if not hasattrAlwaysReturnsTrue(object):
# Add some attributes that don't always get picked up. If
# they don't apply, they'll get filtered out at the end
attributes += ['__bases__', '__class__', '__dict__', '__name__',
'func_closure', 'func_code', 'func_defaults',
'func_dict', 'func_doc', 'func_globals', 'func_name']
if includeMagic:
try: attributes += object._getAttributeNames()
except: pass
# Get all attribute names.
attrdict = getAllAttributeNames(object)
for attrlist in attrdict.values():
attributes += attrlist
# Remove duplicates from the attribute list.
for item in attributes:
dict[item] = None
attributes = dict.keys()
attributes.sort(lambda x, y: cmp(x.upper(), y.upper()))
if not includeSingle:
attributes = filter(lambda item: item[0]!='_' \
or item[1]=='_', attributes)
if not includeDouble:
attributes = filter(lambda item: item[:2]!='__', attributes)
#print "attributes currently", attributes
# Make sure we haven't picked up any bogus attributes somehow.
#attributes = [attribute for attribute in attributes \
# if hasattr(object, attribute)]
retval = []
for attribute in attributes:
#print "checking", attribute
try:
if hasattr(object, attribute):
retval += [attribute]
except:
# yes Virginia, hasattr() can fail in Jython 2.2 because trying
# to get __doc__ on a builtin class results in NullPointerException
pass
return retval
def hasattrAlwaysReturnsTrue(object):
return hasattr(object, 'bogu5_123_aTTri8ute')
def getAllAttributeNames(object):
"""Return dict of all attributes, including inherited, for an object.
Recursively walk through a class and all base classes.
"""
attrdict = {} # (object, technique, count): [list of attributes]
# !!!
# Do Not use hasattr() as a test anywhere in this function,
# because it is unreliable with the remote objects: xmlrpc, soap, etc.
# They always return true for hasattr().
# !!!
try:
# Yes, this can fail if object is an instance of a class with
# __str__ (or __repr__) having a bug or raising an
# exception. :-(
key = str(object)
except:
key = 'anonymous'
# Wake up sleepy object - a hack for ZODB objects in "ghost" state.
try:
wakeupcall = dir(object)
del wakeupcall
except:
pass
# Get attributes available through the normal convention
try:
attributes = dir(object)
attrdict[(key, 'dir', len(attributes))] = attributes
except:
# sadly, this fails for PyReflectedFunctions
pass
# Get attributes rom the object's dictionary, if it has one.
try:
attributes = object.__dict__.keys()
attributes.sort()
except: # Must catch all because object might have __getattr__.
pass
else:
attrdict[(key, '__dict__', len(attributes))] = attributes
# For a class instance, get the attributes for the class.
try:
klass = object.__class__
except: # Must catch all because object might have __getattr__.
pass
else:
if klass is object:
# Break a circular reference. This happens with extension
# classes.
#print "breaking circular reference to self"
pass
# this extra check added for Jython 2.2.1 to break circular recursion
elif klass is not java.lang.Class:
# print "calling update from", object, "with", klass
attrdict.update(getAllAttributeNames(klass))
# Also get attributes from any and all parent classes.
try:
bases = object.__bases__
except: # Must catch all because object might have __getattr__.
pass
else:
if isinstance(bases, types.TupleType):
# needed for Jython 2.2?
halt_type = type(types.TypeType)
for base in bases:
if type(base) is types.TypeType \
or type(base) is halt_type:
# Break a circular reference. Happens in Python 2.2.
#print "breaking TypeType circular reference"
pass
else:
# print "calling update (better not be 'type') with", base
attrdict.update(getAllAttributeNames(base))
return attrdict
def getCallTip(command='', locals=None):
"""For a command, return a tuple of object name, argspec, tip text.
The call tip information will be based on the locals namespace."""
calltip = ('', '', '') # object name, argspec, tip text.
# Get the proper chunk of code from the command.
root = getRoot(command, terminator='(')
try:
if locals is not None:
object = eval(root, locals)
else:
object = eval(root)
except:
#print "could not eval(", root, "):", sys.exc_info()[0]
return calltip
name = ''
object, dropSelf = getBaseObject(object)
try:
name = object.__name__
except AttributeError:
pass
tip1 = ''
argspec = ''
if inspect.isbuiltin(object):
# Builtin function don't have an argspec that we can get.
pass
elif inspect.isfunction(object):
# tip1 is a string like: "getCallTip(command='', locals=None)"
argspec = apply(inspect.formatargspec, inspect.getargspec(object))
if dropSelf:
# Thh first parameter to a method is a reference to an
# instance, usually coded as "self", and is usually passed
# automatically by Python; therefore we want to drop it.
temp = argspec.split(',')
if len(temp) == 1: # No other arguments.
argspec = '()'
else: # Drop the first argument.
argspec = '(' + ','.join(temp[1:]).lstrip()
tip1 = name + argspec
doc = ''
if callable(object):
try:
doc = inspect.getdoc(object)
except:
# Jython 2.2a1 could throw and exception with getdoc()
pass
if doc:
# tip2 is the first separated line of the docstring, like:
# "Return call tip text for a command."
# tip3 is the rest of the docstring, like:
# "The call tip information will be based on ... <snip>
firstline = doc.split('\n')[0].lstrip()
if tip1 == firstline:
tip1 = ''
else:
tip1 += '\n\n'
docpieces = doc.split('\n\n')
tip2 = docpieces[0]
tip3 = '\n\n'.join(docpieces[1:])
tip = '%s%s\n\n%s' % (tip1, tip2, tip3)
else:
tip = tip1
calltip = (name, argspec[1:-1], tip.strip())
return calltip
def getRoot(command, terminator=None):
"""Return the rightmost root portion of an arbitrary Python command.
Return only the root portion that can be eval()ed without side
effect. The command would normally terminate with a '(' or
'.'. The terminator and anything after the terminator will be
dropped."""
command = command.split('\n')[-1]
if command.startswith(sys.ps2):
command = command[len(sys.ps2):]
command = command.lstrip()
command = rtrimTerminus(command, terminator)
tokens = getTokens(command)
if not tokens:
return ''
if tokens[-1][0] is tokenize.ENDMARKER:
# Remove the end marker.
del tokens[-1]
if not tokens:
return ''
if terminator == '.' and \
(tokens[-1][1] <> '.' or tokens[-1][0] is not tokenize.OP):
# Trap decimals in numbers, versus the dot operator
return ''
else:
# Strip off the terminator.
if terminator and command.endswith(terminator):
size = 0 - len(terminator)
command = command[:size]
command = command.rstrip()
tokens = getTokens(command)
tokens.reverse()
line = ''
start = None
prefix = ''
laststring = '.'
emptyTypes = ('[]', '()', '{}')
for token in tokens:
tokentype = token[0]
tokenstring = token[1]
line = token[4]
if tokentype is tokenize.ENDMARKER:
continue
if tokentype in (tokenize.NAME, tokenize.STRING, tokenize.NUMBER) \
and laststring != '.':
# We've reached something that's not part of the root.
if prefix and line[token[3][1]] != ' ':
# If it doesn't have a space after it, remove the prefix.
prefix = ''
break
if tokentype in (tokenize.NAME, tokenize.STRING, tokenize.NUMBER) \
or (tokentype is tokenize.OP and tokenstring == '.'):
if prefix:
# The prefix isn't valid because it comes after a dot.
prefix = ''
break
else:
# start represents the last known good point in the line
start = token[2][1]
elif len(tokenstring) == 1 and tokenstring in ('[({])}'):
# Remember, we're working backwards.
# So prefix += tokenstring would be wrong.
if prefix in emptyTypes and tokenstring in ('[({'):
# We've already got an empty type identified so now we
# are in a nested situation and we can break out with
# what we've got
break
else:
prefix = tokenstring = prefix
else:
# We've reached something that's not part of the root
break
laststring= tokenstring
if start is None:
start = len(line)
root = line[start:]
if prefix in emptyTypes:
# Empty types are safe to be eval()'d and introspected.
root = prefix + root
return root
def getRootAndFilter(command, terminator=None):
"""Return the rightmost root portion of an arbitrary Python command.
Also returns the filter, which is the fragment after the root and
terminator.
Return only the root portion that can be eval()ed without side
effect. The command would normally terminate with a '(' or
'.'. The terminator and anything after the terminator will be
dropped."""
command = command.split('\n')[-1]
if command.startswith(sys.ps2):
command = command[len(sys.ps2):]
command = command.lstrip()
tokens = getTokens(command)
if not tokens:
return ('', '')
tokens.reverse()
root = ""
filter = ""
terminator_seen = False
# initialize matching bracket/paren sets
op_mate = {'}': '{',
']': '[',
')': '('}
op_stack = []
while len(tokens) > 0:
# work backwards through the tokens, starting at the end of the string
token = tokens[0]
del tokens[0]
tokentype = token[0]
tokenstring = token[1]
line = token[4]
if tokentype is tokenize.ENDMARKER:
#println("Hit end marker; continuing")
continue
if not terminator_seen:
if not filter and tokentype in (tokenize.NAME, tokenize.STRING):
# okay, we think we've found our filter string
filter = tokenstring
#println("hit filter string '" + filter + "'")
elif tokenstring == terminator:
# hooray, our terminator!
terminator_seen = True
else:
# either we found another token before our already-set
# filter string, or we just found a bad token
#println("No valid tokens found after terminator (at '" +
# tokenstring + "'")
break
else:
# we've seen the terminator -- continue adding valid tokens
# until we hit a token that stops us
if tokentype in (tokenize.NAME, tokenize.STRING, tokenize.NUMBER):
root = tokenstring + root
#println("Added to root: '" + root + "'")
elif tokentype is tokenize.OP:
if tokenstring in op_mate.keys():
# found a closing bracket/paren
op_stack.append(tokenstring)
elif tokenstring in op_mate.values():
if len(op_stack) < 1 or \
tokenstring != op_mate[op_stack.pop()]:
# uh-oh, non-matching brackets/parens!
break
elif len(op_stack) > 0:
# weird tokens are okay inside brackets/parens
pass
elif tokenstring == '.':
# dots are okay too!
pass
else:
break
root = tokenstring + root
#println("Added to root: '" + root + "'")
else:
# hit a terminating token
break
return (root, filter)
def getTokens(command):
"""Return list of token tuples for command."""
command = str(command) # In case the command is unicode, which fails.
f = cStringIO.StringIO(command)
# tokens is a list of token tuples, each looking like:
# (type, string, (srow, scol), (erow, ecol), line)
tokens = []
# Can't use list comprehension:
# tokens = [token for token in tokenize.generate_tokens(f.readline)]
# because of need to append as much as possible before TokenError.
try:
# This works with Python 2.1.3 (with nested_scopes)
def eater(*args):
tokens.append(args)
tokenize.tokenize_loop(f.readline, eater)
except tokenize.TokenError:
# This is due to a premature EOF, which we expect since we are
# feeding in fragments of Python code
pass
return tokens
def rtrimTerminus(command, terminator=None):
"""Return command minus anything that follows the final terminator."""
if terminator:
pieces = command.split(terminator)
if len(pieces) > 1:
command = terminator.join(pieces[:-1]) + terminator
return command
def getBaseObject(object):
"""Return base object and dropSelf indicator for an object."""
if inspect.isbuiltin(object):
# Builtin function don't have an argspec that we can get.
dropSelf = 0
elif inspect.ismethod(object):
# Get the function from the object otherwise
# inspect.getargspec() complains that the object isn't a
# Python funciton.
try:
if object.im_self is None:
# This is an unbound method so we do not drop self
# from the argpec, sinc ean instance must be passed
# as the first arg.
dropSelf = 0
else:
dropSelf = 1
object = object.im_func
except AttributeError:
dropSelf = 0
elif inspect.isclass(object):
# Get the __init__ method function for the class
constructor = getConstructor(object)
if constructor is not None:
object = constructor
dropSelf = 1
else:
dropSelf = 0
elif callable(object):
# Get the __call__ method instead
try:
call_method = object.__call__.im_func
if call_method.__name__ == '__call__':
# unbound jython method end up here, example: string.index(
dropSelf = 0
else:
object = call_method
dropSelf = 1
except AttributeError:
# unbound python methods end up here
dropSelf = 0
else:
dropSelf = 0
return object, dropSelf
def getConstructor(object):
"""Return constructor for class object, or None if there isn't one."""
try:
return object.__init__.im_func
except AttributeError:
for base in object.__bases__:
constructor = getConstructor(base)
if constructor is not None:
return constructor
return None

View file

@ -0,0 +1,234 @@
"""Extend introspect.py for Java based Jython classes."""
from introspect import *
import string
import __builtin__
import java # needed for java.lang.Class
import org # for org.python.core
import ghidra # for PythonCodeCompletionFactory
__author__ = "Don Coleman <dcoleman@chariotsolutions.com>"
#def getAutoCompleteList(command='', locals=None, includeMagic=1,
# includeSingle=1, includeDouble=1):
# """Return list of auto-completion options for command.
#
# The list of options will be based on the locals namespace."""
# attributes = []
# # Get the proper chunk of code from the command.
# root = getRoot(command, terminator='.')
# try:
# if locals is not None:
# object = eval(root, locals)
# else:
# object = eval(root)
# except:
# #print "could not eval(", root, "):", sys.exc_info()[0]
# return attributes
#
# if ispython(object):
# # use existing code
# attributes = getAttributeNames(object, includeMagic, includeSingle,
# includeDouble)
# else:
# methods = methodsOf(object.__class__)
# attributes = [eachMethod.__name__ for eachMethod in methods]
#
# return attributes
#
#def methodsOf(clazz):
# """Return a list of all the methods in a class"""
# classMembers = vars(clazz).values()
# methods = [eachMember for eachMember in classMembers
# if callable(eachMember)]
# for eachBase in clazz.__bases__:
# methods.extend(methodsOf(eachBase))
# return methods
def getCallTipJava(command='', locals=None):
"""For a command, return a tuple of object name, argspec, tip text.
The call tip information will be based on the locals namespace."""
calltip = ('', '', '') # object name, argspec, tip text.
# Get the proper chunk of code from the command.
(root, filter) = getRootAndFilter(command, terminator='(')
#java.lang.System.out.println("root=" + root)
try:
if locals is not None:
object = eval(root, locals)
else:
object = eval(root)
except:
#java.lang.System.err.println("could not eval(" + root + "):" +
# str(sys.exc_info()[0]))
return calltip
if ispython(object):
# Patrick's code handles Python code
# TODO fix in future because getCallTip runs eval() again
#java.lang.System.out.println("is a Python object")
calltip = getCallTip(command, locals)
if not calltip[1] and not calltip[2]:
# either it's a pure Java object, or we didn't get much from Python's
# getCallTip
name = ''
try:
name = object.__name__
except AttributeError:
pass
tipList = []
argspec = '' # not using argspec for Java
# if inspect.isbuiltin(object):
# # inspect.isbuiltin() fails for Jython
# # Can we get the argspec for Jython builtins? We can't in Python.
# # YES!
# print "is a builtin"
# pass
# elif inspect.isclass(object):
if inspect.isclass(object):
# get the constructor(s)
# TODO consider getting modifiers since Jython can access
# private methods
#java.lang.System.out.println("is a class")
try:
# this will likely fail for pure Python classes
constructors = object.getConstructors()
for constructor in constructors:
paramList = []
paramTypes = constructor.getParameterTypes()
# paramTypes is an array of classes; we need Strings
# TODO consider list comprehension
for param in paramTypes:
# TODO translate [B to byte[], C to char[], etc.
paramList.append(param.__name__)
paramString = string.join(paramList, ', ')
tip = "%s(%s)" % (constructor.name, paramString)
tipList.append(tip)
if len(constructors) == 1:
plural = ""
else:
plural = "s"
name = "Constructor" + plural + " for " + name + ":"
except:
pass
# if callable(object):
# # some Python types are function names as well, like
# # type() and file()
# argspec = str(object.__call__)
# # these don't seem to be very accurate
# if hasattr(object.__call__, "maxargs"):
# tipList.append("maxargs?: " +
# str(object.__call__.maxargs))
# if hasattr(object.__call__, "minargs"):
# tipList.append("minargs?: " +
# str(object.__call__.minargs))
# elif inspect.ismethod(object):
elif inspect.isroutine(object):
#java.lang.System.out.println("is a routine")
# method = object
# object = method.im_class
#
# # Java allows overloading so we may have more than one method
# methodArray = object.getMethods()
#
# for eachMethod in methodArray:
# if eachMethod.name == method.__name__:
# paramList = []
# for eachParam in eachMethod.parameterTypes:
# paramList.append(eachParam.__name__)
#
# paramString = string.join(paramList, ', ')
#
# # create a Python style string a la PyCrust
# # we're showing the parameter type rather than the
# # parameter name, since that's all we can get
# # we need to show multiple methods for overloading
# # TODO improve message format
# # do we want to show the method visibility?
# # how about exceptions?
# # note: name, return type and exceptions same for
# # EVERY overloaded method
#
#
# tip = "%s(%s) -> %s" % (eachMethod.name, paramString,
# eachMethod.returnType)
# tipList.append(tip)
if hasattr(object, "argslist"):
for args in object.argslist:
if args is not None:
# for now
tipList.append(str(args.data))
# elif callable(object):
# argspec = str(object.__call__)
# # these don't seem to be very accurate
# if hasattr(object.__call__, "maxargs"):
# tipList.append("maxargs?: " + str(object.__call__.maxargs))
# if hasattr(object.__call__, "minargs"):
# tipList.append("minargs?: " + str(object.__call__.minargs))
# elif inspect.isfunction(object):
# print "is function"
if (len(tipList) == 0):
if hasattr(object, "__name__") and \
hasattr(__builtin__, object.__name__):
# try to get arguments for any other "old-style" builtin
# functions (see __builtin__.java, classDictInit() method)
methods = \
java.lang.Class.getMethods(org.python.core.__builtin__)
for method in methods:
if method.name == object.__name__:
tipList.append(str(method))
argspec = "a built-in Python function"
else:
# last-ditch: try possible __call__ methods of new-style
# objects
for possible_call_method in \
ghidra.python.PythonCodeCompletionFactory.getCallMethods(object):
signature = str(possible_call_method)
# clean up the method signature a bit, so it looks sane
signature = \
signature.replace("$1exposed_", ".").replace(".__call__", "")
tipList.append(signature)
calltip = (name, argspec, string.join(tipList, "\n"))
return calltip
def ispython(object):
"""
Figure out if this is Python code or Java code..
"""
pyclass = 0
pycode = 0
pyinstance = 0
if inspect.isclass(object):
try:
object.__doc__
pyclass = 1
except AttributeError:
pyclass = 0
elif inspect.ismethod(object):
try:
# changed for Jython 2.2a1
#object.__dict__
object.__str__
pycode = 1
except AttributeError:
pycode = 0
else: # I guess an instance of an object falls here
try:
# changed for Jython 2.2a1
#object.__dict__
object.__str__
pyinstance = 1
except AttributeError:
pyinstance = 0
return pyclass | pycode | pyinstance

View file

@ -0,0 +1,33 @@
"""
User-supplied customizations go here.
"""
# nice-to-have: place 'java' and 'ghidra' into the local namespace, so you
# can do fun things like "dir(java.lang)"
import java
import ghidra
import __main__
__main__.java = java
__main__.ghidra = ghidra
# fix Jython "bug": unknown type 'javainstance' or 'javapackage' even though
# that is the type Jython gives us if we ask type(<someObject>) or
# type(ghidra) (respectively)
import __builtin__
import org.python.core
# changed by Jim 20090528 for Jython 2.5
# not sure why I even put these here... the first one might be troublesome
#__builtin__.javainstance = org.python.core.PyJavaInstance
#__builtin__.javapackage = org.python.core.PyJavaPackage
#__builtin__.javaclass = org.python.core.PyJavaClass
__builtin__.javainstance = org.python.core.PyObjectDerived
__builtin__.javapackage = org.python.core.PyJavaPackage
__builtin__.javaclass = org.python.core.PyJavaType
# changed by Jim 20090528 for Jython 2.5
# REMOVED collections stuff
# OOPS still need this
import sys
# Ghidra documentation
import ghidradoc