diff options
Diffstat (limited to 'python/lldbutils')
-rw-r--r-- | python/lldbutils/.ruff.toml | 4 | ||||
-rw-r--r-- | python/lldbutils/README.txt | 221 | ||||
-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 |
8 files changed, 632 insertions, 0 deletions
diff --git a/python/lldbutils/.ruff.toml b/python/lldbutils/.ruff.toml new file mode 100644 index 0000000000..7c7717fa13 --- /dev/null +++ b/python/lldbutils/.ruff.toml @@ -0,0 +1,4 @@ +extend = "../../pyproject.toml" + +[isort] +known-first-party = ["lldbutils"] diff --git a/python/lldbutils/README.txt b/python/lldbutils/README.txt new file mode 100644 index 0000000000..fd7e90675c --- /dev/null +++ b/python/lldbutils/README.txt @@ -0,0 +1,221 @@ +lldb debugging functionality for Gecko +====================================== + +This directory contains a module, lldbutils, which is imported by the +in-tree .lldbinit file. The lldbutil modules define some lldb commands +that are handy for debugging Gecko. + +If you want to add a new command or Python-implemented type summary, either add +it to one of the existing broad area Python files (such as lldbutils/layout.py +for layout-related commands) or create a new file if none of the existing files +is appropriate. If you add a new file, make sure you add it to __all__ in +lldbutils/__init__.py. + + +Supported commands +------------------ + +Most commands below that can take a pointer to an object also support being +called with a smart pointer like nsRefPtr or nsCOMPtr. + + +* frametree EXPR, ft EXPR + frametreelimited EXPR, ftl EXPR + + Shows information about a frame tree. EXPR is an expression that + is evaluated, and must be an nsIFrame*. frametree displays the + entire frame tree that contains the given frame. frametreelimited + displays a subtree of the frame tree rooted at the given frame. + + (lldb) p this + (nsBlockFrame *) $4 = 0x000000011687fcb8 + (lldb) ftl this + Block(div)(-1)@0x11687fcb8 {0,0,7380,690} [state=0002100000d04601] [content=0x11688c0c0] [sc=0x11687f990:-moz-scrolled-content]< + line 0x116899130: count=1 state=inline,clean,prevmarginclean,not impacted,not wrapped,before:nobr,after:nobr[0x100] {60,0,0,690} ink-overflow=60,510,0,0 scr-overflow=60,510,0,0 < + Text(0)""@0x1168990c0 {60,510,0,0} [state=0001000020404000] [content=0x11687ca10] [sc=0x11687fd88:-moz-non-element,parent=0x11687eb00] [run=0x115115e80][0,0,T] + > + > + (lldb) ft this + Viewport(-1)@0x116017430 [view=0x115efe190] {0,0,60,60} [state=000b063000002623] [sc=0x1160170f8:-moz-viewport]< + HTMLScroll(html)(-1)@0x1160180d0 {0,0,0,0} [state=000b020000000403] [content=0x115e4d640] [sc=0x116017768:-moz-viewport-scroll]< + ... + Canvas(html)(-1)@0x116017e08 {0,0,60,60} ink-overflow=0,0,8340,2196 scr-overflow=0,0,8220,2196 [state=000b002000000601] [content=0x115e4d640] [sc=0x11687e0f8:-moz-scrolled-canvas]< + Block(html)(-1)@0x11687e578 {0,0,60,2196} ink-overflow=0,0,8340,2196 scr-overflow=0,0,8220,2196 [state=000b100000d00601] [content=0x115e4d640] [sc=0x11687e4b8,parent=0x0]< + line 0x11687ec48: count=1 state=block,clean,prevmarginclean,not impacted,not wrapped,before:nobr,after:nobr[0x48] bm=480 {480,480,0,1236} ink-overflow=360,426,7980,1410 scr-overflow=480,480,7740,1236 < + Block(body)(1)@0x11687ebb0 {480,480,0,1236} ink-overflow=-120,-54,7980,1410 scr-overflow=0,0,7740,1236 [state=000b120000100601] [content=0x115ed8980] [sc=0x11687e990]< + line 0x116899170: count=1 state=inline,clean,prevmarginclean,not impacted,not wrapped,before:nobr,after:nobr[0x0] {0,0,7740,1236} ink-overflow=-120,-54,7980,1410 scr-overflow=0,0,7740,1236 < + nsTextControlFrame@0x11687f068 {0,66,7740,1170} ink-overflow=-120,-120,7980,1410 scr-overflow=0,0,7740,1170 [state=0002000000004621] [content=0x115ca2c50] [sc=0x11687ea40]< + HTMLScroll(div)(-1)@0x11687f6b0 {180,240,7380,690} [state=0002000000084409] [content=0x11688c0c0] [sc=0x11687eb00]< + Block(div)(-1)@0x11687fcb8 {0,0,7380,690} [state=0002100000d04601] [content=0x11688c0c0] [sc=0x11687f990:-moz-scrolled-content]< + line 0x116899130: count=1 state=inline,clean,prevmarginclean,not impacted,not wrapped,before:nobr,after:nobr[0x100] {60,0,0,690} ink-overflow=60,510,0,0 scr-overflow=60,510,0,0 < + Text(0)""@0x1168990c0 {60,510,0,0} [state=0001000020404000] [content=0x11687ca10] [sc=0x11687fd88:-moz-non-element,parent=0x11687eb00] [run=0x115115e80][0,0,T] + ... + + +* js + + Dumps the current JS stack. + + (lldb) js + 0 anonymous(aForce = false) ["chrome://browser/content/browser.js":13414] + this = [object Object] + 1 updateAppearance() ["chrome://browser/content/browser.js":13326] + this = [object Object] + 2 handleEvent(aEvent = [object Event]) ["chrome://browser/content/tabbrowser.xml":3811] + this = [object XULElement] + + +* prefcnt EXPR + + Shows the refcount of a given object. EXPR is an expression that is + evaluated, and can be either a pointer to or an actual refcounted + object. The object can be a standard nsISupports-like refcounted + object, a cycle-collected object or a mozilla::RefCounted<T> object. + + (lldb) p this + (nsHTMLDocument *) $1 = 0x0000000116e9d800 + (lldb) prefcnt this + 20 + (lldb) p mDocumentURI + (nsCOMPtr<nsIURI>) $3 = { + mRawPtr = 0x0000000117163e50 + } + (lldb) prefcnt mDocumentURI + 11 + + +* pstate EXPR + + Shows the frame state bits (using their symbolic names) of a given frame. + EXPR is an expression that is evaluated, and must be an nsIFrame*. + + (lldb) p this + (nsTextFrame *) $1 = 0x000000011f470b10 + (lldb) p/x mState + (nsFrameState) $2 = 0x0000004080604000 + (lldb) pstate this + TEXT_HAS_NONCOLLAPSED_CHARACTERS | TEXT_END_OF_LINE | TEXT_START_OF_LINE | NS_FRAME_PAINTED_THEBES | NS_FRAME_INDEPENDENT_SELECTION + + +* ptag EXPR + + Shows the DOM tag name of a node. EXPR is an expression that is + evaluated, and can be either an nsINode pointer or a concrete DOM + object. + + (lldb) p this + (nsHTMLDocument *) $0 = 0x0000000116e9d800 + (lldb) ptag this + (PermanentAtomImpl *) $1 = 0x0000000110133ac0 u"#document" + (lldb) p this->GetRootElement() + (mozilla::dom::HTMLSharedElement *) $2 = 0x0000000118429780 + (lldb) ptag $2 + (PermanentAtomImpl *) $3 = 0x0000000110123b80 u"html" + + +Supported type summaries and synthetic children +----------------------------------------------- + +In lldb terminology, type summaries are rules for how to display a value +when using the "expression" command (or its familiar-to-gdb-users "p" alias), +and synthetic children are fake member variables or array elements also +added by custom rules. + +For objects that do have synthetic children defined for them, like nsTArray, +the "expr -R -- EXPR" command can be used to show its actual member variables. + + +* nsAString, nsACString, + nsFixedString, nsFixedCString, + nsAutoString, nsAutoCString + + Strings have a type summary that shows the actual string. + + (lldb) frame info + frame #0: 0x000000010400cfea XUL`nsCSSParser::ParseProperty(this=0x00007fff5fbf5248, aPropID=eCSSProperty_margin_top, aPropValue=0x00007fff5fbf53f8, aSheetURI=0x0000000115ae8c00, aBaseURI=0x0000000115ae8c00, aSheetPrincipal=0x000000010ff9e040, aDeclaration=0x00000001826fd580, aChanged=0x00007fff5fbf5247, aIsImportant=false, aIsSVGMode=false) + 74 at nsCSSParser.cpp:12851 + (lldb) p aPropValue + (const nsAString) $16 = u"-25px" + + (lldb) p this + (nsHTMLDocument *) $18 = 0x0000000115b56000 + (lldb) p mContentType + (nsCString) $19 = { + nsACString = "text/html" + } + +* nscolor + + nscolors (32-bit RGBA colors) have a type summary that shows the color as + one of the CSS 2.1 color keywords, a six digit hex color, an rgba() color, + or the "transparent" keyword. + + (lldb) p this + (nsTextFrame *) $0 = 0x00000001168245e0 + (lldb) p *this->StyleColor() + (const nsStyleColor) $1 = { + mColor = lime + } + (lldb) expr -R -- *this->StyleColor() + (const nsStyleColor) $2 = { + mColor = 4278255360 + } + +* nsIAtom + + Atoms have a type summary that shows the string value inside the atom. + + (lldb) frame info + frame #0: 0x00000001028b8c49 XUL`mozilla::dom::Element::GetBoolAttr(this=0x0000000115ca1c50, aAttr=0x000000011012a640) const + 25 at Element.h:907 + (lldb) p aAttr + (PermanentAtomImpl *) $1 = 0x000000011012a640 u"readonly" + +* nsTArray and friends + + nsTArrays and their auto and fallible varieties have synthetic children + for their elements. This means when displaying them with "expr" (or "p"), + they will be shown like regular arrays, rather than showing the mHdr and + other fields. + + (lldb) frame info + frame #0: 0x00000001043eb8a8 XUL`SVGTextFrame::DoGlyphPositioning(this=0x000000012f3f8778) + 248 at SVGTextFrame.cpp:4940 + (lldb) p charPositions + (nsTArray<nsPoint>) $5 = { + [0] = { + mozilla::gfx::BasePoint<int, nsPoint> = { + x = 0 + y = 816 + } + } + [1] = { + mozilla::gfx::BasePoint<int, nsPoint> = { + x = 426 + y = 816 + } + } + [2] = { + mozilla::gfx::BasePoint<int, nsPoint> = { + x = 906 + y = 816 + } + } + } + (lldb) expr -R -- charPositions + (nsTArray<nsPoint>) $4 = { + nsTArray_Impl<nsPoint, nsTArrayInfallibleAllocator> = { + nsTArray_base<nsTArrayInfallibleAllocator, nsTArray_CopyWithMemutils> = { + mHdr = 0x000000012f3f1b80 + } + } + } + +* nsTextNode, nsTextFragment + + Text nodes have a type summary that shows the nsTextFragment in the + nsTextNode, which itself has a type summary that shows the text + content. + + (lldb) p this + (nsTextFrame *) $14 = 0x000000011811bb10 + (lldb) p mContent + (nsTextNode *) $15 = 0x0000000118130110 "Search or enter address" + 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 |