123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174 |
- #
- # Author: Zoltan Varga (vargaz@gmail.com)
- # License: MIT/X11
- #
- #
- # This is a mono support mode for lldb
- #
- # Comments about the lldb python api:
- # - there are no accessors, i.e. valobj["name"]
- # - http://lldb.llvm.org/python_reference/index.html seems to be outdated
- # - there is no autoload support, i.e. can't load this file automatically
- # when 'mono' is the debugger target.
- import lldb
- # FIXME: Generate enums from runtime enums
- MONO_TYPE_END = 0x00
- MONO_TYPE_VOID = 0x01
- MONO_TYPE_BOOLEAN = 0x02
- MONO_TYPE_CHAR = 0x03
- MONO_TYPE_I1 = 0x04
- MONO_TYPE_U1 = 0x05
- MONO_TYPE_I2 = 0x06
- MONO_TYPE_U2 = 0x07
- MONO_TYPE_I4 = 0x08
- MONO_TYPE_U4 = 0x09
- MONO_TYPE_I8 = 0x0a
- MONO_TYPE_U8 = 0x0b
- MONO_TYPE_R4 = 0x0c
- MONO_TYPE_R8 = 0x0d
- MONO_TYPE_STRING = 0x0e
- MONO_TYPE_PTR = 0x0f
- MONO_TYPE_BYREF = 0x10
- MONO_TYPE_VALUETYPE = 0x11
- MONO_TYPE_CLASS = 0x12
- MONO_TYPE_VAR = 0x13
- MONO_TYPE_ARRAY = 0x14
- MONO_TYPE_GENERICINST= 0x15
- MONO_TYPE_TYPEDBYREF = 0x16
- MONO_TYPE_I = 0x18
- MONO_TYPE_U = 0x19
- MONO_TYPE_FNPTR = 0x1b
- MONO_TYPE_OBJECT = 0x1c
- MONO_TYPE_SZARRAY = 0x1d
- MONO_TYPE_MVAR = 0x1e
- primitive_type_names = {
- MONO_TYPE_BOOLEAN : "bool",
- MONO_TYPE_CHAR : "char",
- MONO_TYPE_I1 : "sbyte",
- MONO_TYPE_U1 : "byte",
- MONO_TYPE_I2 : "short",
- MONO_TYPE_U2 : "ushort",
- MONO_TYPE_I4 : "int",
- MONO_TYPE_U4 : "uint",
- MONO_TYPE_I8 : "long",
- MONO_TYPE_U8 : "ulong",
- MONO_TYPE_R4 : "float",
- MONO_TYPE_R8 : "double",
- MONO_TYPE_STRING : "string"
- }
- #
- # Helper functions for working with the lldb python api
- #
- def member(val, member_name):
- return val.GetChildMemberWithName (member_name)
- def string_member(val, member_name):
- return val.GetChildMemberWithName (member_name).GetSummary ()[1:-1]
- def isnull(val):
- return val.deref.addr.GetOffset () == 0
- def stringify_class_name(ns, name):
- if ns == "System":
- if name == "Byte":
- return "byte"
- if name == "String":
- return "string"
- if ns == "":
- return name
- else:
- return "{0}.{1}".format (ns, name)
- #
- # Pretty printers for mono runtime types
- #
- def stringify_type (type):
- "Print a MonoType structure"
- ttype = member(type, "type").GetValueAsUnsigned()
- if primitive_type_names.has_key (ttype):
- return primitive_type_names [ttype]
- else:
- return "<MonoTypeEnum 0x{0:x}>".format (ttype)
- def stringify_ginst (ginst):
- "Print a MonoGenericInst structure"
- len = int(member(ginst, "type_argc").GetValue())
- argv = member(ginst, "type_argv")
- res=""
- for i in range(len):
- t = argv.GetChildAtIndex(i, False, True)
- if i > 0:
- res += ", "
- res += stringify_type(t)
- return res
- def print_type(valobj, internal_dict):
- type = valobj
- if isnull (type):
- return ""
- return stringify_type (type)
- def print_class (valobj, internal_dict):
- klass = valobj
- if isnull (klass):
- return ""
- aname = member (member (member (klass, "image"), "assembly"), "aname")
- basename = "[{0}]{1}".format (string_member (aname, "name"), (stringify_class_name (string_member (klass, "name_space"), string_member (klass, "name"))))
- gclass = member (klass, "generic_class")
- if not isnull (gclass):
- ginst = member (member (gclass, "context"), "class_inst")
- return "{0}<{1}>".format (basename, stringify_ginst (ginst))
- return basename
- def print_method (valobj, internal_dict):
- method = valobj
- if isnull (method):
- return ""
- klass = member (method, "klass")
- return "{0}:{1}()".format (print_class (klass, None), string_member (valobj, "name"))
- def print_domain(valobj, internal_dict):
- domain = valobj
- if isnull (domain):
- return ""
- target = domain.target
- root = target.FindFirstGlobalVariable("mono_root_domain")
- name = string_member (domain, "friendly_name")
- if root.IsValid () and root.deref.addr.GetOffset () == root.deref.addr.GetOffset ():
- return "[root]"
- else:
- return "[{0}]".format (name)
- def print_object(valobj, internal_dict):
- obj = valobj
- if isnull (obj):
- return ""
- domain = member (member (obj, "vtable"), "domain")
- klass = member (member (obj, "vtable"), "klass")
- return print_domain (domain, None) + print_class (klass, None)
- # Register pretty printers
- # FIXME: This cannot pick up the methods define in this module, leading to warnings
- lldb.debugger.HandleCommand ("type summary add -w mono -F mono.print_method MonoMethod")
- lldb.debugger.HandleCommand ("type summary add -w mono -F mono.print_class MonoClass")
- lldb.debugger.HandleCommand ("type summary add -w mono -F mono.print_type MonoType")
- lldb.debugger.HandleCommand ("type summary add -w mono -F mono.print_domain MonoDomain")
- lldb.debugger.HandleCommand ("type summary add -w mono -F mono.print_object MonoObject")
- lldb.debugger.HandleCommand ("type category enable mono")
- # Helper commands for runtime debugging
- # These resume the target
- # Print the method at the current ip
- lldb.debugger.HandleCommand ("command alias pip p mono_print_method_from_ip((void*)$pc)")
- # Print the method at the provided ip
- lldb.debugger.HandleCommand ("command regex pmip 's/^$/p mono_print_method_from_ip((void*)$pc)/' 's/(.+)/p mono_print_method_from_ip((void*)(%1))/'")
- print "Mono support mode loaded."
|