]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - examples/python/diagnose_nsstring.py
Vendor import of lldb trunk r256945:
[FreeBSD/FreeBSD.git] / examples / python / diagnose_nsstring.py
1 # This implements the "diagnose-nsstring" command, usually installed in the debug session like
2 #   command script import lldb.diagnose
3 # it is used when NSString summary formatter fails to replicate the logic that went into LLDB making the
4 # decisions it did and  providing some useful context information that can be used for improving the formatter
5
6 import lldb
7
8 def read_memory(process,location,size):
9         data = ""
10         error = lldb.SBError()
11         for x in range(0,size-1):
12                 byte = process.ReadUnsignedFromMemory(x+location,1,error)
13                 if error.fail:
14                         data = data + "err%s" % "" if x == size-2 else ":"
15                 else:
16                         try:
17                                 data = data + "0x%x" % byte
18                                 if byte == 0:
19                                         data = data + "(\\0)"
20                                 elif byte == 0xa:
21                                         data = data + "(\\a)"
22                                 elif byte == 0xb:
23                                         data = data + "(\\b)"
24                                 elif byte == 0xc:
25                                         data = data + "(\\c)"
26                                 elif byte == '\n':
27                                         data = data + "(\\n)"
28                                 else:
29                                         data = data + "(%s)" % chr(byte)
30                                 if x < size-2:
31                                         data = data + ":"
32                         except Exception as e:
33                                 print e
34         return data
35
36 def diagnose_nsstring_Command_Impl(debugger,command,result,internal_dict):
37         """
38         A command to diagnose the LLDB NSString data formatter
39         invoke as
40         (lldb) diagnose-nsstring <expr returning NSString>
41         e.g.
42         (lldb) diagnose-nsstring @"Hello world"
43         """
44         target = debugger.GetSelectedTarget()
45         process = target.GetProcess()
46         thread = process.GetSelectedThread()
47         frame = thread.GetSelectedFrame()
48         if not target.IsValid() or not process.IsValid():
49                 return "unable to get target/process - cannot proceed"
50         options = lldb.SBExpressionOptions()
51         options.SetFetchDynamicValue()
52         error = lldb.SBError()
53         if frame.IsValid():
54                 nsstring = frame.EvaluateExpression(command,options)
55         else:
56                 nsstring = target.EvaluateExpression(command,options)
57         print >>result,str(nsstring)
58         nsstring_address = nsstring.GetValueAsUnsigned(0)
59         if nsstring_address == 0:
60                 return "unable to obtain the string - cannot proceed"
61         expression = "\
62 struct $__lldb__notInlineMutable {\
63     char* buffer;\
64     signed long length;\
65     signed long capacity;\
66     unsigned int hasGap:1;\
67     unsigned int isFixedCapacity:1;\
68     unsigned int isExternalMutable:1;\
69     unsigned int capacityProvidedExternally:1;\n\
70 #if __LP64__\n\
71     unsigned long desiredCapacity:60;\n\
72 #else\n\
73     unsigned long desiredCapacity:28;\n\
74 #endif\n\
75     void* contentsAllocator;\
76 };\
77 \
78 struct $__lldb__CFString {\
79     void* _cfisa;\
80     uint8_t _cfinfo[4];\
81     uint32_t _rc;\
82     union {\
83         struct __inline1 {\
84             signed long length;\
85         } inline1;\
86         struct __notInlineImmutable1 {\
87             char* buffer;\
88             signed long length;\
89             void* contentsDeallocator;\
90         } notInlineImmutable1;\
91         struct __notInlineImmutable2 {\
92             char* buffer;\
93             void* contentsDeallocator;\
94         } notInlineImmutable2;\
95         struct $__lldb__notInlineMutable notInlineMutable;\
96     } variants;\
97 };\
98 "
99
100         expression = expression + "*(($__lldb__CFString*) %d)" % nsstring_address
101         # print expression
102         dumped = target.EvaluateExpression(expression,options)
103         print >>result, str(dumped)
104         
105         little_endian = (target.byte_order == lldb.eByteOrderLittle)
106         ptr_size = target.addr_size
107         
108         info_bits = dumped.GetChildMemberWithName("_cfinfo").GetChildAtIndex(0 if little_endian else 3).GetValueAsUnsigned(0)
109         is_mutable = (info_bits & 1) == 1
110         is_inline = (info_bits & 0x60) == 0
111         has_explicit_length = (info_bits & (1 | 4)) != 4
112         is_unicode = (info_bits & 0x10) == 0x10
113         is_special = (nsstring.GetDynamicValue(lldb.eDynamicCanRunTarget).GetTypeName() == "NSPathStore2")
114         has_null = (info_bits & 8) == 8
115     
116         print >>result,"\nInfo=%d\nMutable=%s\nInline=%s\nExplicit=%s\nUnicode=%s\nSpecial=%s\nNull=%s\n" % \
117                 (info_bits, "yes" if is_mutable else "no","yes" if is_inline else "no","yes" if has_explicit_length else "no","yes" if is_unicode else "no","yes" if is_special else "no","yes" if has_null else "no")
118
119
120         explicit_length_offset = 0
121         if not has_null and has_explicit_length and not is_special:
122                 explicit_length_offset = 2*ptr_size
123                 if is_mutable and not is_inline:
124                         explicit_length_offset = explicit_length_offset + ptr_size
125                 elif is_inline:
126                         pass
127                 elif not is_inline and not is_mutable:
128                         explicit_length_offset = explicit_length_offset + ptr_size
129                 else:
130                         explicit_length_offset = 0
131
132         if explicit_length_offset == 0:
133                 print >>result,"There is no explicit length marker - skipping this step\n"
134         else:
135                 explicit_length_offset = nsstring_address + explicit_length_offset
136                 explicit_length = process.ReadUnsignedFromMemory(explicit_length_offset, 4, error)
137                 print >>result,"Explicit length location is at 0x%x - read value is %d\n" % (explicit_length_offset,explicit_length)
138
139         if is_mutable:
140                 location = 2 * ptr_size + nsstring_address
141                 location = process.ReadPointerFromMemory(location,error)
142         elif is_inline and has_explicit_length and not is_unicode and not is_special and not is_mutable:
143                 location = 3 * ptr_size + nsstring_address
144         elif is_unicode:
145                 location = 2 * ptr_size + nsstring_address
146                 if is_inline:
147                         if not has_explicit_length:
148                                 print >>result,"Unicode & Inline & !Explicit is a new combo - no formula for it"
149                         else:
150                                 location += ptr_size
151                 else:
152                         location = process.ReadPointerFromMemory(location,error)
153         elif is_special:
154                 location = nsstring_address + ptr_size + 4
155         elif is_inline:
156                 location = 2 * ptr_size + nsstring_address
157                 if not has_explicit_length:
158                         location += 1
159         else:
160                 location = 2 * ptr_size + nsstring_address
161                 location = process.ReadPointerFromMemory(location,error)
162         print >>result,"Expected data location: 0x%x\n" % (location)
163         print >>result,"1K of data around location: %s\n" % read_memory(process,location,1024)
164         print >>result,"5K of data around string pointer: %s\n" % read_memory(process,nsstring_address,1024*5)
165
166 def __lldb_init_module(debugger, internal_dict):
167         debugger.HandleCommand("command script add -f %s.diagnose_nsstring_Command_Impl diagnose-nsstring" % __name__)
168         print 'The "diagnose-nsstring" command has been installed, type "help diagnose-nsstring" for detailed help.'
169
170 __lldb_init_module(lldb.debugger,None)
171 __lldb_init_module = None