# # 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 "".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."