mono.py 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. #
  2. # Author: Zoltan Varga (vargaz@gmail.com)
  3. # License: MIT/X11
  4. #
  5. #
  6. # This is a mono support mode for lldb
  7. #
  8. # Comments about the lldb python api:
  9. # - there are no accessors, i.e. valobj["name"]
  10. # - http://lldb.llvm.org/python_reference/index.html seems to be outdated
  11. # - there is no autoload support, i.e. can't load this file automatically
  12. # when 'mono' is the debugger target.
  13. import lldb
  14. # FIXME: Generate enums from runtime enums
  15. MONO_TYPE_END = 0x00
  16. MONO_TYPE_VOID = 0x01
  17. MONO_TYPE_BOOLEAN = 0x02
  18. MONO_TYPE_CHAR = 0x03
  19. MONO_TYPE_I1 = 0x04
  20. MONO_TYPE_U1 = 0x05
  21. MONO_TYPE_I2 = 0x06
  22. MONO_TYPE_U2 = 0x07
  23. MONO_TYPE_I4 = 0x08
  24. MONO_TYPE_U4 = 0x09
  25. MONO_TYPE_I8 = 0x0a
  26. MONO_TYPE_U8 = 0x0b
  27. MONO_TYPE_R4 = 0x0c
  28. MONO_TYPE_R8 = 0x0d
  29. MONO_TYPE_STRING = 0x0e
  30. MONO_TYPE_PTR = 0x0f
  31. MONO_TYPE_BYREF = 0x10
  32. MONO_TYPE_VALUETYPE = 0x11
  33. MONO_TYPE_CLASS = 0x12
  34. MONO_TYPE_VAR = 0x13
  35. MONO_TYPE_ARRAY = 0x14
  36. MONO_TYPE_GENERICINST= 0x15
  37. MONO_TYPE_TYPEDBYREF = 0x16
  38. MONO_TYPE_I = 0x18
  39. MONO_TYPE_U = 0x19
  40. MONO_TYPE_FNPTR = 0x1b
  41. MONO_TYPE_OBJECT = 0x1c
  42. MONO_TYPE_SZARRAY = 0x1d
  43. MONO_TYPE_MVAR = 0x1e
  44. primitive_type_names = {
  45. MONO_TYPE_BOOLEAN : "bool",
  46. MONO_TYPE_CHAR : "char",
  47. MONO_TYPE_I1 : "sbyte",
  48. MONO_TYPE_U1 : "byte",
  49. MONO_TYPE_I2 : "short",
  50. MONO_TYPE_U2 : "ushort",
  51. MONO_TYPE_I4 : "int",
  52. MONO_TYPE_U4 : "uint",
  53. MONO_TYPE_I8 : "long",
  54. MONO_TYPE_U8 : "ulong",
  55. MONO_TYPE_R4 : "float",
  56. MONO_TYPE_R8 : "double",
  57. MONO_TYPE_STRING : "string"
  58. }
  59. #
  60. # Helper functions for working with the lldb python api
  61. #
  62. def member(val, member_name):
  63. return val.GetChildMemberWithName (member_name)
  64. def string_member(val, member_name):
  65. return val.GetChildMemberWithName (member_name).GetSummary ()[1:-1]
  66. def isnull(val):
  67. return val.deref.addr.GetOffset () == 0
  68. def stringify_class_name(ns, name):
  69. if ns == "System":
  70. if name == "Byte":
  71. return "byte"
  72. if name == "String":
  73. return "string"
  74. if ns == "":
  75. return name
  76. else:
  77. return "{0}.{1}".format (ns, name)
  78. #
  79. # Pretty printers for mono runtime types
  80. #
  81. def stringify_type (type):
  82. "Print a MonoType structure"
  83. ttype = member(type, "type").GetValueAsUnsigned()
  84. if primitive_type_names.has_key (ttype):
  85. return primitive_type_names [ttype]
  86. else:
  87. return "<MonoTypeEnum 0x{0:x}>".format (ttype)
  88. def stringify_ginst (ginst):
  89. "Print a MonoGenericInst structure"
  90. len = int(member(ginst, "type_argc").GetValue())
  91. argv = member(ginst, "type_argv")
  92. res=""
  93. for i in range(len):
  94. t = argv.GetChildAtIndex(i, False, True)
  95. if i > 0:
  96. res += ", "
  97. res += stringify_type(t)
  98. return res
  99. def print_type(valobj, internal_dict):
  100. type = valobj
  101. if isnull (type):
  102. return ""
  103. return stringify_type (type)
  104. def print_class (valobj, internal_dict):
  105. klass = valobj
  106. if isnull (klass):
  107. return ""
  108. aname = member (member (member (klass, "image"), "assembly"), "aname")
  109. basename = "[{0}]{1}".format (string_member (aname, "name"), (stringify_class_name (string_member (klass, "name_space"), string_member (klass, "name"))))
  110. gclass = member (klass, "generic_class")
  111. if not isnull (gclass):
  112. ginst = member (member (gclass, "context"), "class_inst")
  113. return "{0}<{1}>".format (basename, stringify_ginst (ginst))
  114. return basename
  115. def print_method (valobj, internal_dict):
  116. method = valobj
  117. if isnull (method):
  118. return ""
  119. klass = member (method, "klass")
  120. return "{0}:{1}()".format (print_class (klass, None), string_member (valobj, "name"))
  121. def print_domain(valobj, internal_dict):
  122. domain = valobj
  123. if isnull (domain):
  124. return ""
  125. target = domain.target
  126. root = target.FindFirstGlobalVariable("mono_root_domain")
  127. name = string_member (domain, "friendly_name")
  128. if root.IsValid () and root.deref.addr.GetOffset () == root.deref.addr.GetOffset ():
  129. return "[root]"
  130. else:
  131. return "[{0}]".format (name)
  132. def print_object(valobj, internal_dict):
  133. obj = valobj
  134. if isnull (obj):
  135. return ""
  136. domain = member (member (obj, "vtable"), "domain")
  137. klass = member (member (obj, "vtable"), "klass")
  138. return print_domain (domain, None) + print_class (klass, None)
  139. # Register pretty printers
  140. # FIXME: This cannot pick up the methods define in this module, leading to warnings
  141. lldb.debugger.HandleCommand ("type summary add -w mono -F mono.print_method MonoMethod")
  142. lldb.debugger.HandleCommand ("type summary add -w mono -F mono.print_class MonoClass")
  143. lldb.debugger.HandleCommand ("type summary add -w mono -F mono.print_type MonoType")
  144. lldb.debugger.HandleCommand ("type summary add -w mono -F mono.print_domain MonoDomain")
  145. lldb.debugger.HandleCommand ("type summary add -w mono -F mono.print_object MonoObject")
  146. lldb.debugger.HandleCommand ("type category enable mono")
  147. # Helper commands for runtime debugging
  148. # These resume the target
  149. # Print the method at the current ip
  150. lldb.debugger.HandleCommand ("command alias pip p mono_print_method_from_ip((void*)$pc)")
  151. # Print the method at the provided ip
  152. lldb.debugger.HandleCommand ("command regex pmip 's/^$/p mono_print_method_from_ip((void*)$pc)/' 's/(.+)/p mono_print_method_from_ip((void*)(%1))/'")
  153. print "Mono support mode loaded."