1# Any copyright is dedicated to the Public Domain.
2# http://creativecommons.org/publicdomain/zero/1.0/
3
4from __future__ import absolute_import, print_function
5import lldb
6from lldbutils import utils
7
8
9def summarize_string(valobj, internal_dict):
10    data = valobj.GetChildMemberWithName("mData")
11    length = valobj.GetChildMemberWithName("mLength").GetValueAsUnsigned(0)
12    return utils.format_string(data, length)
13
14
15def summarize_atom(valobj, internal_dict):
16    target = lldb.debugger.GetSelectedTarget()
17    length = valobj.GetChildMemberWithName("mLength").GetValueAsUnsigned()
18    string = target.EvaluateExpression(
19        "(char16_t*)%s.GetUTF16String()" % valobj.GetName()
20    )
21    return utils.format_string(string, length)
22
23
24class TArraySyntheticChildrenProvider:
25    def __init__(self, valobj, internal_dict):
26        self.valobj = valobj
27        self.header = self.valobj.GetChildMemberWithName("mHdr")
28        self.element_type = self.valobj.GetType().GetTemplateArgumentType(0)
29        self.element_size = self.element_type.GetByteSize()
30        header_size = self.header.GetType().GetPointeeType().GetByteSize()
31        self.element_base_addr = self.header.GetValueAsUnsigned(0) + header_size
32
33    def num_children(self):
34        return (
35            self.header.Dereference()
36            .GetChildMemberWithName("mLength")
37            .GetValueAsUnsigned(0)
38        )
39
40    def get_child_index(self, name):
41        try:
42            index = int(name)
43            if index >= self.num_children():
44                return None
45        # Ideally we'd use the exception type, but it's unclear what that is
46        # without knowing how to trigger the original exception.
47        except:  # NOQA: E501, E722
48            pass
49        return None
50
51    def get_child_at_index(self, index):
52        if index >= self.num_children():
53            return None
54        addr = self.element_base_addr + index * self.element_size
55        return self.valobj.CreateValueFromAddress(
56            "[%d]" % index, addr, self.element_type
57        )
58
59
60def prefcnt(debugger, command, result, dict):
61    """Displays the refcount of an object."""
62    # We handled regular nsISupports-like refcounted objects and cycle collected
63    # objects.
64    target = debugger.GetSelectedTarget()
65    process = target.GetProcess()
66    thread = process.GetSelectedThread()
67    frame = thread.GetSelectedFrame()
68    obj = frame.EvaluateExpression(command)
69    if obj.GetError().Fail():
70        print("could not evaluate expression")
71        return
72    obj = utils.dereference(obj)
73    field = obj.GetChildMemberWithName("mRefCnt")
74    if field.GetError().Fail():
75        field = obj.GetChildMemberWithName("refCnt")
76    if field.GetError().Fail():
77        print("not a refcounted object")
78        return
79    refcnt_type = field.GetType().GetCanonicalType().GetName()
80    if refcnt_type == "nsAutoRefCnt":
81        print(field.GetChildMemberWithName("mValue").GetValueAsUnsigned(0))
82    elif refcnt_type == "nsCycleCollectingAutoRefCnt":
83        print(
84            field.GetChildMemberWithName("mRefCntAndFlags").GetValueAsUnsigned(0) >> 2
85        )
86    elif refcnt_type == "mozilla::ThreadSafeAutoRefCnt":
87        print(
88            field.GetChildMemberWithName("mValue")
89            .GetChildMemberWithName("mValue")
90            .GetValueAsUnsigned(0)
91        )
92    elif refcnt_type == "int":  # non-atomic mozilla::RefCounted object
93        print(field.GetValueAsUnsigned(0))
94    elif refcnt_type == "mozilla::Atomic<int>":  # atomic mozilla::RefCounted object
95        print(field.GetChildMemberWithName("mValue").GetValueAsUnsigned(0))
96    else:
97        print("unknown mRefCnt type " + refcnt_type)
98
99
100# Used to work around http://llvm.org/bugs/show_bug.cgi?id=22211
101def callfunc(debugger, command, result, dict):
102    """Calls a function for which debugger information is unavailable by getting its address
103    from the symbol table.  The function is assumed to return void."""
104
105    if "(" not in command:
106        print("Usage: callfunc your_function(args)")
107        return
108
109    command_parts = command.split("(")
110    funcname = command_parts[0].strip()
111    args = command_parts[1]
112
113    target = debugger.GetSelectedTarget()
114    symbols = target.FindFunctions(funcname).symbols
115    if not symbols:
116        print('Could not find a function symbol for a function called "%s"' % funcname)
117        return
118
119    sym = symbols[0]
120    arg_types = "()"
121    if sym.name and sym.name.startswith(funcname + "("):
122        arg_types = sym.name[len(funcname) :]
123    debugger.HandleCommand(
124        "print ((void(*)%s)0x%0x)(%s"
125        % (arg_types, sym.addr.GetLoadAddress(target), args)
126    )
127
128
129def init(debugger):
130    debugger.HandleCommand(
131        "type summary add nsAString -F lldbutils.general.summarize_string"
132    )
133    debugger.HandleCommand(
134        "type summary add nsACString -F lldbutils.general.summarize_string"
135    )
136    debugger.HandleCommand(
137        "type summary add nsFixedString -F lldbutils.general.summarize_string"
138    )
139    debugger.HandleCommand(
140        "type summary add nsFixedCString -F lldbutils.general.summarize_string"
141    )
142    debugger.HandleCommand(
143        "type summary add nsAutoString -F lldbutils.general.summarize_string"
144    )
145    debugger.HandleCommand(
146        "type summary add nsAutoCString -F lldbutils.general.summarize_string"
147    )
148    debugger.HandleCommand(
149        "type summary add nsAtom -F lldbutils.general.summarize_atom"
150    )
151    debugger.HandleCommand(
152        'type synthetic add -x "nsTArray<" -l lldbutils.general.TArraySyntheticChildrenProvider'
153    )
154    debugger.HandleCommand(
155        'type synthetic add -x "AutoTArray<" -l lldbutils.general.TArraySyntheticChildrenProvider'  # NOQA: E501
156    )
157    debugger.HandleCommand(
158        'type synthetic add -x "FallibleTArray<" -l lldbutils.general.TArraySyntheticChildrenProvider'  # NOQA: E501
159    )
160    debugger.HandleCommand(
161        "command script add -f lldbutils.general.prefcnt -f lldbutils.general.prefcnt prefcnt"
162    )
163    debugger.HandleCommand(
164        "command script add -f lldbutils.general.callfunc -f lldbutils.general.callfunc callfunc"
165    )
166