diff options
Diffstat (limited to 'python/lldbutils/lldbutils')
-rw-r--r-- | python/lldbutils/lldbutils/__init__.py | 17 | ||||
-rw-r--r-- | python/lldbutils/lldbutils/content.py | 28 | ||||
-rw-r--r-- | python/lldbutils/lldbutils/general.py | 165 | ||||
-rw-r--r-- | python/lldbutils/lldbutils/gfx.py | 65 | ||||
-rw-r--r-- | python/lldbutils/lldbutils/layout.py | 46 | ||||
-rw-r--r-- | python/lldbutils/lldbutils/utils.py | 86 |
6 files changed, 407 insertions, 0 deletions
diff --git a/python/lldbutils/lldbutils/__init__.py b/python/lldbutils/lldbutils/__init__.py new file mode 100644 index 0000000000..e1263153df --- /dev/null +++ b/python/lldbutils/lldbutils/__init__.py @@ -0,0 +1,17 @@ +# Any copyright is dedicated to the Public Domain. +# http://creativecommons.org/publicdomain/zero/1.0/ + +import lldb + +__all__ = ["content", "general", "gfx", "layout", "utils"] + + +def init(): + for name in __all__: + init = None + try: + init = __import__("lldbutils." + name, globals(), locals(), ["init"]).init + except AttributeError: + pass + if init: + init(lldb.debugger) diff --git a/python/lldbutils/lldbutils/content.py b/python/lldbutils/lldbutils/content.py new file mode 100644 index 0000000000..8f2bf22ccd --- /dev/null +++ b/python/lldbutils/lldbutils/content.py @@ -0,0 +1,28 @@ +# Any copyright is dedicated to the Public Domain. +# http://creativecommons.org/publicdomain/zero/1.0/ + +from lldbutils import utils + + +def summarize_text_fragment(valobj, internal_dict): + content_union = valobj.GetChildAtIndex(0) + state_union = valobj.GetChildAtIndex(1).GetChildMemberWithName("mState") + length = state_union.GetChildMemberWithName("mLength").GetValueAsUnsigned(0) + if state_union.GetChildMemberWithName("mIs2b").GetValueAsUnsigned(0): + field = "m2b" + else: + field = "m1b" + ptr = content_union.GetChildMemberWithName(field) + return utils.format_string(ptr, length) + + +def ptag(debugger, command, result, dict): + """Displays the tag name of a content node.""" + debugger.HandleCommand("expr (" + command + ")->mNodeInfo.mRawPtr->mInner.mName") + + +def init(debugger): + debugger.HandleCommand( + "type summary add nsTextFragment -F lldbutils.content.summarize_text_fragment" + ) + debugger.HandleCommand("command script add -f lldbutils.content.ptag ptag") diff --git a/python/lldbutils/lldbutils/general.py b/python/lldbutils/lldbutils/general.py new file mode 100644 index 0000000000..577b3847fa --- /dev/null +++ b/python/lldbutils/lldbutils/general.py @@ -0,0 +1,165 @@ +# Any copyright is dedicated to the Public Domain. +# http://creativecommons.org/publicdomain/zero/1.0/ + +import lldb + +from lldbutils import utils + + +def summarize_string(valobj, internal_dict): + data = valobj.GetChildMemberWithName("mData") + length = valobj.GetChildMemberWithName("mLength").GetValueAsUnsigned(0) + return utils.format_string(data, length) + + +def summarize_atom(valobj, internal_dict): + target = lldb.debugger.GetSelectedTarget() + length = valobj.GetChildMemberWithName("mLength").GetValueAsUnsigned() + string = target.EvaluateExpression( + "(char16_t*)%s.GetUTF16String()" % valobj.GetName() + ) + return utils.format_string(string, length) + + +class TArraySyntheticChildrenProvider: + def __init__(self, valobj, internal_dict): + self.valobj = valobj + self.header = self.valobj.GetChildMemberWithName("mHdr") + self.element_type = self.valobj.GetType().GetTemplateArgumentType(0) + self.element_size = self.element_type.GetByteSize() + header_size = self.header.GetType().GetPointeeType().GetByteSize() + self.element_base_addr = self.header.GetValueAsUnsigned(0) + header_size + + def num_children(self): + return ( + self.header.Dereference() + .GetChildMemberWithName("mLength") + .GetValueAsUnsigned(0) + ) + + def get_child_index(self, name): + try: + index = int(name) + if index >= self.num_children(): + return None + # Ideally we'd use the exception type, but it's unclear what that is + # without knowing how to trigger the original exception. + except: # NOQA: E501, E722 + pass + return None + + def get_child_at_index(self, index): + if index >= self.num_children(): + return None + addr = self.element_base_addr + index * self.element_size + return self.valobj.CreateValueFromAddress( + "[%d]" % index, addr, self.element_type + ) + + +def prefcnt(debugger, command, result, dict): + """Displays the refcount of an object.""" + # We handled regular nsISupports-like refcounted objects and cycle collected + # objects. + target = debugger.GetSelectedTarget() + process = target.GetProcess() + thread = process.GetSelectedThread() + frame = thread.GetSelectedFrame() + obj = frame.EvaluateExpression(command) + if obj.GetError().Fail(): + print("could not evaluate expression") + return + obj = utils.dereference(obj) + field = obj.GetChildMemberWithName("mRefCnt") + if field.GetError().Fail(): + field = obj.GetChildMemberWithName("refCnt") + if field.GetError().Fail(): + print("not a refcounted object") + return + refcnt_type = field.GetType().GetCanonicalType().GetName() + if refcnt_type == "nsAutoRefCnt": + print(field.GetChildMemberWithName("mValue").GetValueAsUnsigned(0)) + elif refcnt_type == "nsCycleCollectingAutoRefCnt": + print( + field.GetChildMemberWithName("mRefCntAndFlags").GetValueAsUnsigned(0) >> 2 + ) + elif refcnt_type == "mozilla::ThreadSafeAutoRefCnt": + print( + field.GetChildMemberWithName("mValue") + .GetChildMemberWithName("mValue") + .GetValueAsUnsigned(0) + ) + elif refcnt_type == "int": # non-atomic mozilla::RefCounted object + print(field.GetValueAsUnsigned(0)) + elif refcnt_type == "mozilla::Atomic<int>": # atomic mozilla::RefCounted object + print(field.GetChildMemberWithName("mValue").GetValueAsUnsigned(0)) + else: + print("unknown mRefCnt type " + refcnt_type) + + +# Used to work around http://llvm.org/bugs/show_bug.cgi?id=22211 +def callfunc(debugger, command, result, dict): + """Calls a function for which debugger information is unavailable by getting its address + from the symbol table. The function is assumed to return void.""" + + if "(" not in command: + print("Usage: callfunc your_function(args)") + return + + command_parts = command.split("(") + funcname = command_parts[0].strip() + args = command_parts[1] + + target = debugger.GetSelectedTarget() + symbols = target.FindFunctions(funcname).symbols + if not symbols: + print('Could not find a function symbol for a function called "%s"' % funcname) + return + + sym = symbols[0] + arg_types = "()" + if sym.name and sym.name.startswith(funcname + "("): + arg_types = sym.name[len(funcname) :] + debugger.HandleCommand( + "print ((void(*)%s)0x%0x)(%s" + % (arg_types, sym.addr.GetLoadAddress(target), args) + ) + + +def init(debugger): + debugger.HandleCommand( + "type summary add nsAString -F lldbutils.general.summarize_string" + ) + debugger.HandleCommand( + "type summary add nsACString -F lldbutils.general.summarize_string" + ) + debugger.HandleCommand( + "type summary add nsFixedString -F lldbutils.general.summarize_string" + ) + debugger.HandleCommand( + "type summary add nsFixedCString -F lldbutils.general.summarize_string" + ) + debugger.HandleCommand( + "type summary add nsAutoString -F lldbutils.general.summarize_string" + ) + debugger.HandleCommand( + "type summary add nsAutoCString -F lldbutils.general.summarize_string" + ) + debugger.HandleCommand( + "type summary add nsAtom -F lldbutils.general.summarize_atom" + ) + debugger.HandleCommand( + 'type synthetic add -x "nsTArray<" -l lldbutils.general.TArraySyntheticChildrenProvider' + ) + debugger.HandleCommand( + 'type synthetic add -x "AutoTArray<" -l lldbutils.general.TArraySyntheticChildrenProvider' # NOQA: E501 + ) + debugger.HandleCommand( + 'type synthetic add -x "FallibleTArray<" -l lldbutils.general.TArraySyntheticChildrenProvider' # NOQA: E501 + ) + debugger.HandleCommand( + "command script add -f lldbutils.general.prefcnt -f lldbutils.general.prefcnt prefcnt" + ) + debugger.HandleCommand( + "command script add -f lldbutils.general.callfunc -f lldbutils.general.callfunc callfunc" + ) diff --git a/python/lldbutils/lldbutils/gfx.py b/python/lldbutils/lldbutils/gfx.py new file mode 100644 index 0000000000..7622dd4f9c --- /dev/null +++ b/python/lldbutils/lldbutils/gfx.py @@ -0,0 +1,65 @@ +# Any copyright is dedicated to the Public Domain. +# http://creativecommons.org/publicdomain/zero/1.0/ + + +def summarize_nscolor(valobj, internal_dict): + colors = { + "#800000": "maroon", + "#ff0000": "red", + "#ffa500": "orange", + "#ffff00": "yellow", + "#808000": "olive", + "#800080": "purple", + "#ff00ff": "fuchsia", + "#ffffff": "white", + "#00ff00": "lime", + "#008000": "green", + "#000080": "navy", + "#0000ff": "blue", + "#00ffff": "aqua", + "#008080": "teal", + "#000000": "black", + "#c0c0c0": "silver", + "#808080": "gray", + } + value = valobj.GetValueAsUnsigned(0) + if value == 0: + return "transparent" + if value & 0xFF000000 != 0xFF000000: + return "rgba(%d, %d, %d, %f)" % ( + value & 0xFF, + (value >> 8) & 0xFF, + (value >> 16) & 0xFF, + ((value >> 24) & 0xFF) / 255.0, + ) + color = "#%02x%02x%02x" % (value & 0xFF, (value >> 8) & 0xFF, (value >> 16) & 0xFF) + if color in colors: + return colors[color] + return color + + +def summarize_rect(valobj, internal_dict): + x = valobj.GetChildMemberWithName("x").GetValue() + y = valobj.GetChildMemberWithName("y").GetValue() + width = valobj.GetChildMemberWithName("width").GetValue() + height = valobj.GetChildMemberWithName("height").GetValue() + return "%s, %s, %s, %s" % (x, y, width, height) + + +def rect_is_empty(valobj): + width = valobj.GetChildMemberWithName("width").GetValueAsSigned() + height = valobj.GetChildMemberWithName("height").GetValueAsSigned() + return width <= 0 or height <= 0 + + +def init(debugger): + debugger.HandleCommand( + "type summary add nscolor -v -F lldbutils.gfx.summarize_nscolor" + ) + debugger.HandleCommand("type summary add nsRect -v -F lldbutils.gfx.summarize_rect") + debugger.HandleCommand( + "type summary add nsIntRect -v -F lldbutils.gfx.summarize_rect" + ) + debugger.HandleCommand( + "type summary add gfxRect -v -F lldbutils.gfx.summarize_rect" + ) diff --git a/python/lldbutils/lldbutils/layout.py b/python/lldbutils/lldbutils/layout.py new file mode 100644 index 0000000000..c70216bff5 --- /dev/null +++ b/python/lldbutils/lldbutils/layout.py @@ -0,0 +1,46 @@ +# Any copyright is dedicated to the Public Domain. +# http://creativecommons.org/publicdomain/zero/1.0/ + + +def frametree(debugger, command, result, dict): + """Dumps the frame tree containing the given nsIFrame*.""" + debugger.HandleCommand("expr (" + command + ")->DumpFrameTree()") + + +def frametree_pixels(debugger, command, result, dict): + """Dumps the frame tree containing the given nsIFrame* in CSS pixels.""" + debugger.HandleCommand("expr (" + command + ")->DumpFrameTreeInCSSPixels()") + + +def frametreelimited(debugger, command, result, dict): + """Dumps the subtree of a frame tree rooted at the given nsIFrame*.""" + debugger.HandleCommand("expr (" + command + ")->DumpFrameTreeLimited()") + + +def frametreelimited_pixels(debugger, command, result, dict): + """Dumps the subtree of a frame tree rooted at the given nsIFrame* + in CSS pixels.""" + debugger.HandleCommand("expr (" + command + ")->DumpFrameTreeLimitedInCSSPixels()") + + +def pstate(debugger, command, result, dict): + """Displays a frame's state bits symbolically.""" + debugger.HandleCommand("expr mozilla::PrintFrameState(" + command + ")") + + +def init(debugger): + debugger.HandleCommand("command script add -f lldbutils.layout.frametree frametree") + debugger.HandleCommand( + "command script add -f lldbutils.layout.frametree_pixels frametree_pixels" + ) + debugger.HandleCommand( + "command script add -f lldbutils.layout.frametreelimited frametreelimited" + ) + debugger.HandleCommand( + "command script add -f lldbutils.layout.frametreelimited_pixels frametreelimited_pixels" + ) + debugger.HandleCommand("command alias ft frametree") + debugger.HandleCommand("command alias ftp frametree_pixels") + debugger.HandleCommand("command alias ftl frametreelimited") + debugger.HandleCommand("command alias ftlp frametreelimited_pixels") + debugger.HandleCommand("command script add -f lldbutils.layout.pstate pstate") diff --git a/python/lldbutils/lldbutils/utils.py b/python/lldbutils/lldbutils/utils.py new file mode 100644 index 0000000000..fdcf7da366 --- /dev/null +++ b/python/lldbutils/lldbutils/utils.py @@ -0,0 +1,86 @@ +# Any copyright is dedicated to the Public Domain. +# http://creativecommons.org/publicdomain/zero/1.0/ + + +def format_char(c): + if c == 0: + return "\\0" + elif c == 0x07: + return "\\a" + elif c == 0x08: + return "\\b" + elif c == 0x0C: + return "\\f" + elif c == 0x0A: + return "\\n" + elif c == 0x0D: + return "\\r" + elif c == 0x09: + return "\\t" + elif c == 0x0B: + return "\\v" + elif c == 0x5C: + return "\\" + elif c == 0x22: + return '\\"' + elif c == 0x27: + return "\\'" + elif c < 0x20 or c >= 0x80 and c <= 0xFF: + return "\\x%02x" % c + elif c >= 0x0100: + return "\\u%04x" % c + else: + return chr(c) + + +# Take an SBValue that is either a char* or char16_t* and formats it like lldb +# would when printing it. +def format_string(lldb_value, length=100): + ptr = lldb_value.GetValueAsUnsigned(0) + char_type = lldb_value.GetType().GetPointeeType() + if char_type.GetByteSize() == 1: + s = '"' + size = 1 + mask = 0xFF + elif char_type.GetByteSize() == 2: + s = 'u"' + size = 2 + mask = 0xFFFF + else: + return "(cannot format string with char type %s)" % char_type.GetName() + i = 0 + terminated = False + while i < length: + c = ( + lldb_value.CreateValueFromAddress( + "x", ptr + i * size, char_type + ).GetValueAsUnsigned(0) + & mask + ) + if c == 0: + terminated = True + break + s += format_char(c) + i = i + 1 + s += '"' + if not terminated and i != length: + s += "..." + return s + + +# Dereferences a raw pointer, nsCOMPtr, RefPtr, nsAutoPtr, already_AddRefed or +# mozilla::RefPtr; otherwise returns the value unchanged. +def dereference(lldb_value): + if lldb_value.TypeIsPointerType(): + return lldb_value.Dereference() + name = lldb_value.GetType().GetUnqualifiedType().GetName() + if ( + name.startswith("nsCOMPtr<") + or name.startswith("RefPtr<") + or name.startswith("nsAutoPtr<") + or name.startswith("already_AddRefed<") + ): + return lldb_value.GetChildMemberWithName("mRawPtr") + if name.startswith("mozilla::RefPtr<"): + return lldb_value.GetChildMemberWithName("ptr") + return lldb_value |