]>
Commit | Line | Data |
---|---|---|
1 | #!/usr/bin/python | |
2 | # | |
3 | ||
4 | #source of register info is from http://opensource.apple.com/source/gdb/gdb-962/src/gdb/arm-tdep.c | |
5 | import lldb | |
6 | import struct | |
7 | osplugin_target_obj = None | |
8 | ||
9 | class PluginValue(lldb.SBValue): | |
10 | def GetChildMemberWithName(val, name): | |
11 | val_type = val.GetType() | |
12 | if val_type.IsPointerType() == True: | |
13 | val_type = val_type.GetPointeeType() | |
14 | for i in range(val_type.GetNumberOfFields()): | |
15 | if name == val_type.GetFieldAtIndex(i).GetName(): | |
16 | return PluginValue(val.GetChildAtIndex(i)) | |
17 | return None | |
18 | ||
19 | ||
20 | class Armv7_RegisterSet(object): | |
21 | """ register info set for armv7 32 bit architecture """ | |
22 | def __init__(self): | |
23 | self.register_info = {} | |
24 | self.register_info['sets'] = ['GPR'] | |
25 | self.register_info['registers'] = [ | |
26 | { 'name':'r0' , 'bitsize' : 32, 'offset' : 0, 'encoding':'uint', 'format':'hex', 'set':0, 'gcc': 0, 'dwarf' : 0}, | |
27 | { 'name':'r1' , 'bitsize' : 32, 'offset' : 4, 'encoding':'uint', 'format':'hex', 'set':0, 'gcc': 1, 'dwarf' : 1}, | |
28 | { 'name':'r2' , 'bitsize' : 32, 'offset' : 8, 'encoding':'uint', 'format':'hex', 'set':0, 'gcc': 2, 'dwarf' : 2}, | |
29 | { 'name':'r3' , 'bitsize' : 32, 'offset' : 12, 'encoding':'uint', 'format':'hex', 'set':0, 'gcc': 3, 'dwarf' : 3}, | |
30 | { 'name':'r4' , 'bitsize' : 32, 'offset' : 16, 'encoding':'uint', 'format':'hex', 'set':0, 'gcc': 4, 'dwarf' : 4}, | |
31 | { 'name':'r5' , 'bitsize' : 32, 'offset' : 20, 'encoding':'uint', 'format':'hex', 'set':0, 'gcc': 5, 'dwarf' : 5}, | |
32 | { 'name':'r6' , 'bitsize' : 32, 'offset' : 24, 'encoding':'uint', 'format':'hex', 'set':0, 'gcc': 6, 'dwarf' : 6}, | |
33 | { 'name':'r7' , 'bitsize' : 32, 'offset' : 28, 'encoding':'uint', 'format':'hex', 'set':0, 'gcc': 7, 'dwarf' : 7}, | |
34 | { 'name':'r8' , 'bitsize' : 32, 'offset' : 32, 'encoding':'uint', 'format':'hex', 'set':0, 'gcc': 8, 'dwarf' : 8}, | |
35 | { 'name':'r9' , 'bitsize' : 32, 'offset' : 36, 'encoding':'uint', 'format':'hex', 'set':0, 'gcc': 9, 'dwarf' : 9}, | |
36 | { 'name':'r10' , 'bitsize' : 32, 'offset' : 40, 'encoding':'uint', 'format':'hex', 'set':0, 'gcc':10, 'dwarf' :10}, | |
37 | { 'name':'r11' , 'bitsize' : 32, 'offset' : 44, 'encoding':'uint', 'format':'hex', 'set':0, 'gcc':11, 'dwarf' :11, 'alt-name': 'fp', 'generic': 'fp'}, | |
38 | { 'name':'r12' , 'bitsize' : 32, 'offset' : 48, 'encoding':'uint', 'format':'hex', 'set':0, 'gcc':12, 'dwarf' :12}, | |
39 | { 'name':'sp' , 'bitsize' : 32, 'offset' : 52, 'encoding':'uint', 'format':'hex', 'set':0, 'gcc':13, 'dwarf' :13, 'alt-name': 'sp', 'generic': 'sp'}, | |
40 | { 'name':'lr' , 'bitsize' : 32, 'offset' : 56, 'encoding':'uint', 'format':'hex', 'set':0, 'gcc':14, 'dwarf' :14, 'alt-name': 'lr', 'generic': 'lr'}, | |
41 | { 'name':'pc' , 'bitsize' : 32, 'offset' : 60, 'encoding':'uint', 'format':'hex', 'set':0, 'gcc':15, 'dwarf' :15, 'alt-name': 'pc', 'generic': 'pc'}, | |
42 | { 'name':'cpsr' , 'bitsize' : 32, 'offset' : 64, 'encoding':'uint', 'format':'hex', 'set':0, 'gcc':25, 'dwarf' :16, 'alt-name':'cpsr','generic':'cpsr'}, | |
43 | { 'name':'fsr' , 'bitsize' : 32, 'offset' : 68, 'encoding':'uint', 'format':'hex', 'set':0, 'gcc':17, 'dwarf' :17, 'alt-name':'fsr', 'generic': 'fsr'}, | |
44 | { 'name':'far' , 'bitsize' : 32, 'offset' : 72, 'encoding':'uint', 'format':'hex', 'set':0, 'gcc':18, 'dwarf' :18, 'alt-name': 'far', 'generic': 'far'} | |
45 | ] | |
46 | self.switch_context_address = osplugin_target_obj.FindSymbols('load_reg')[0].GetSymbol().GetStartAddress().GetLoadAddress(osplugin_target_obj) + 8 | |
47 | self.ResetRegisterValues() | |
48 | def ResetRegisterValues(self): | |
49 | self.r0 = 0 | |
50 | self.r1 = 0 | |
51 | self.r2 = 0 | |
52 | self.r3 = 0 | |
53 | self.r4 = 0 | |
54 | self.r5 = 0 | |
55 | self.r6 = 0 | |
56 | self.r7 = 0 | |
57 | self.r8 = 0 | |
58 | self.r9 = 0 | |
59 | self.r10 = 0 | |
60 | self.r11 = 0 | |
61 | self.r12 = 0 | |
62 | self.sp = 0 | |
63 | self.lr = 0 | |
64 | self.pc = 0 | |
65 | self.cpsr = 0 | |
66 | self.fsr = 0 | |
67 | self.far = 0 | |
68 | ||
69 | def __str__(self): | |
70 | return """ | |
71 | r0 = {o.r0: <#010x} | |
72 | r1 = {o.r1: <#010x} | |
73 | r2 = {o.r2: <#010x} | |
74 | r3 = {o.r3: <#010x} | |
75 | r4 = {o.r4: <#010x} | |
76 | r5 = {o.r5: <#010x} | |
77 | r6 = {o.r6: <#010x} | |
78 | r7 = {o.r7: <#010x} | |
79 | r8 = {o.r8: <#010x} | |
80 | r9 = {o.r9: <#010x} | |
81 | r10 = {o.r10: <#010x} | |
82 | r11 = {o.r11: <#010x} | |
83 | r12 = {o.r12: <#010x} | |
84 | sp = {o.sp: <#010x} | |
85 | lr = {o.lr: <#010x} | |
86 | pc = {o.pc: <#010x} | |
87 | cpsr = {o.cpsr: <#010x} | |
88 | fsr = {o.fsr : <#010x} | |
89 | far = {o.far : <#010x} | |
90 | """.format(o=self) | |
91 | ||
92 | def GetPackedRegisterState(self): | |
93 | return struct.pack('19I', self.r0, self.r1, self.r2, self.r3, | |
94 | self.r4, self.r5, self.r6, self.r7, | |
95 | self.r8, self.r9, self.r10, self.r11, | |
96 | self.r12, self.sp, self.lr, self.pc, | |
97 | self.cpsr, self.fsr, self.far) | |
98 | ||
99 | def ReadRegisterDataFromKDPSavedState(self, kdp_state, kernel_version): | |
100 | saved_state = kernel_version.CreateValueFromExpression(None, '(struct arm_saved_state *) ' + str(kdp_state.GetValueAsUnsigned())) | |
101 | saved_state = saved_state.Dereference() | |
102 | saved_state = PluginValue(saved_state) | |
103 | self.ResetRegisterValues() | |
104 | self.r0 = saved_state.GetChildMemberWithName('r').GetChildAtIndex(0).GetValueAsUnsigned() | |
105 | self.r1 = saved_state.GetChildMemberWithName('r').GetChildAtIndex(1).GetValueAsUnsigned() | |
106 | self.r2 = saved_state.GetChildMemberWithName('r').GetChildAtIndex(2).GetValueAsUnsigned() | |
107 | self.r3 = saved_state.GetChildMemberWithName('r').GetChildAtIndex(3).GetValueAsUnsigned() | |
108 | self.r4 = saved_state.GetChildMemberWithName('r').GetChildAtIndex(4).GetValueAsUnsigned() | |
109 | self.r5 = saved_state.GetChildMemberWithName('r').GetChildAtIndex(5).GetValueAsUnsigned() | |
110 | self.r6 = saved_state.GetChildMemberWithName('r').GetChildAtIndex(6).GetValueAsUnsigned() | |
111 | self.r7 = saved_state.GetChildMemberWithName('r').GetChildAtIndex(7).GetValueAsUnsigned() | |
112 | self.r8 = saved_state.GetChildMemberWithName('r').GetChildAtIndex(8).GetValueAsUnsigned() | |
113 | self.r9 = saved_state.GetChildMemberWithName('r').GetChildAtIndex(9).GetValueAsUnsigned() | |
114 | self.r10 = saved_state.GetChildMemberWithName('r').GetChildAtIndex(10).GetValueAsUnsigned() | |
115 | self.r11 = saved_state.GetChildMemberWithName('r').GetChildAtIndex(11).GetValueAsUnsigned() | |
116 | self.r12 = saved_state.GetChildMemberWithName('r').GetChildAtIndex(12).GetValueAsUnsigned() | |
117 | self.sp = saved_state.GetChildMemberWithName('sp').GetValueAsUnsigned() | |
118 | self.lr = saved_state.GetChildMemberWithName('lr').GetValueAsUnsigned() | |
119 | self.pc = saved_state.GetChildMemberWithName('pc').GetValueAsUnsigned() | |
120 | self.cpsr = saved_state.GetChildMemberWithName('cpsr').GetValueAsUnsigned() | |
121 | self.fsr = saved_state.GetChildMemberWithName('fsr').GetValueAsUnsigned() | |
122 | self.far = saved_state.GetChildMemberWithName('far').GetValueAsUnsigned() | |
123 | return self | |
124 | ||
125 | def ReadRegisterDataFromKernelStack(self, kstack_saved_state_addr, kernel_version): | |
126 | saved_state = kernel_version.CreateValueFromExpression(None, '(struct arm_saved_state *) '+ str(kstack_saved_state_addr)) | |
127 | saved_state = saved_state.Dereference() | |
128 | saved_state = PluginValue(saved_state) | |
129 | self.ResetRegisterValues() | |
130 | self.r0 = saved_state.GetChildMemberWithName('r').GetChildAtIndex(0).GetValueAsUnsigned() | |
131 | self.r1 = saved_state.GetChildMemberWithName('r').GetChildAtIndex(1).GetValueAsUnsigned() | |
132 | self.r2 = saved_state.GetChildMemberWithName('r').GetChildAtIndex(2).GetValueAsUnsigned() | |
133 | self.r3 = saved_state.GetChildMemberWithName('r').GetChildAtIndex(3).GetValueAsUnsigned() | |
134 | self.r4 = saved_state.GetChildMemberWithName('r').GetChildAtIndex(4).GetValueAsUnsigned() | |
135 | self.r5 = saved_state.GetChildMemberWithName('r').GetChildAtIndex(5).GetValueAsUnsigned() | |
136 | self.r6 = saved_state.GetChildMemberWithName('r').GetChildAtIndex(6).GetValueAsUnsigned() | |
137 | self.r7 = saved_state.GetChildMemberWithName('r').GetChildAtIndex(7).GetValueAsUnsigned() | |
138 | self.r8 = saved_state.GetChildMemberWithName('r').GetChildAtIndex(8).GetValueAsUnsigned() | |
139 | self.r9 = saved_state.GetChildMemberWithName('r').GetChildAtIndex(9).GetValueAsUnsigned() | |
140 | self.r10 = saved_state.GetChildMemberWithName('r').GetChildAtIndex(10).GetValueAsUnsigned() | |
141 | self.r11 = saved_state.GetChildMemberWithName('r').GetChildAtIndex(11).GetValueAsUnsigned() | |
142 | self.r12 = saved_state.GetChildMemberWithName('r').GetChildAtIndex(12).GetValueAsUnsigned() | |
143 | self.sp = saved_state.GetChildMemberWithName('sp').GetValueAsUnsigned() | |
144 | self.lr = saved_state.GetChildMemberWithName('lr').GetValueAsUnsigned() | |
145 | # pc for a blocked thread is treated to be the next instruction it would run after thread switch. | |
146 | self.pc = self.switch_context_address | |
147 | self.cpsr = saved_state.GetChildMemberWithName('cpsr').GetValueAsUnsigned() | |
148 | self.fsr = saved_state.GetChildMemberWithName('fsr').GetValueAsUnsigned() | |
149 | self.far = saved_state.GetChildMemberWithName('far').GetValueAsUnsigned() | |
150 | return self | |
151 | ||
152 | def ReadRegisterDataFromContinuation(self, continuation_ptr): | |
153 | self.ResetRegisterValues() | |
154 | self.pc = continuation_ptr | |
155 | return self | |
156 | ||
157 | ||
158 | class I386_RegisterSet(object): | |
159 | """ register info set for i386 architecture | |
160 | """ | |
161 | def __init__(self): | |
162 | self.register_info = [] | |
163 | self.register_info['sets'] = ['GPR'] | |
164 | self.register_info['registers'] = [ | |
165 | { 'name': 'eax' , 'bitsize': 32, 'offset' : 0, 'encoding': 'uint' , 'format':'hex' , 'set': 0, 'gcc' : 0, 'dwarf': 0}, | |
166 | { 'name': 'ebx' , 'bitsize': 32, 'offset' : 4, 'encoding': 'uint' , 'format':'hex' , 'set': 0, 'gcc' : 1, 'dwarf': 1}, | |
167 | { 'name': 'ecx' , 'bitsize': 32, 'offset' : 8, 'encoding': 'uint' , 'format':'hex' , 'set': 0, 'gcc' : 2, 'dwarf': 2}, | |
168 | { 'name': 'edx' , 'bitsize': 32, 'offset' :12, 'encoding': 'uint' , 'format':'hex' , 'set': 0, 'gcc' : 3, 'dwarf': 3}, | |
169 | { 'name': 'edi' , 'bitsize': 32, 'offset' :16, 'encoding': 'uint' , 'format':'hex' , 'set': 0, 'gcc' : 4, 'dwarf': 4}, | |
170 | { 'name': 'esi' , 'bitsize': 32, 'offset' :20, 'encoding': 'uint' , 'format':'hex' , 'set': 0, 'gcc' : 5, 'dwarf': 5}, | |
171 | { 'name': 'ebp' , 'bitsize': 32, 'offset' :24, 'encoding': 'uint' , 'format':'hex' , 'set': 0, 'gcc' : 6, 'dwarf': 6}, | |
172 | { 'name': 'esp' , 'bitsize': 32, 'offset' :28, 'encoding': 'uint' , 'format':'hex' , 'set': 0, 'gcc' : 7, 'dwarf': 7}, | |
173 | { 'name': 'ss' , 'bitsize': 32, 'offset' :32, 'encoding': 'uint' , 'format':'hex' , 'set': 0, 'gcc' : 8, 'dwarf': 8}, | |
174 | { 'name': 'eflags', 'bitsize': 32, 'offset' :36, 'encoding': 'uint' , 'format':'hex' , 'set': 0, 'gcc' : 9, 'dwarf': 9}, | |
175 | { 'name': 'eip' , 'bitsize': 32, 'offset' :40, 'encoding': 'uint' , 'format':'hex' , 'set': 0, 'gcc' :10, 'dwarf':10}, | |
176 | { 'name': 'cs' , 'bitsize': 32, 'offset' :44, 'encoding': 'uint' , 'format':'hex' , 'set': 0, 'gcc' :11, 'dwarf':11}, | |
177 | { 'name': 'ds' , 'bitsize': 32, 'offset' :48, 'encoding': 'uint' , 'format':'hex' , 'set': 0, 'gcc' :12, 'dwarf':12}, | |
178 | { 'name': 'es' , 'bitsize': 32, 'offset' :52, 'encoding': 'uint' , 'format':'hex' , 'set': 0, 'gcc' :13, 'dwarf':13}, | |
179 | { 'name': 'fs' , 'bitsize': 32, 'offset' :56, 'encoding': 'uint' , 'format':'hex' , 'set': 0, 'gcc' :14, 'dwarf':14}, | |
180 | { 'name': 'gs' , 'bitsize': 32, 'offset' :60, 'encoding': 'uint' , 'format':'hex' , 'set': 0, 'gcc' :15, 'dwarf':15}, | |
181 | ] | |
182 | self.ResetRegisterValues() | |
183 | def ResetRegisterValues(self): | |
184 | """ set all registers to zero """ | |
185 | self.eax = 0 | |
186 | self.ebx = 0 | |
187 | self.ecx = 0 | |
188 | self.edx = 0 | |
189 | self.edi = 0 | |
190 | self.esi = 0 | |
191 | self.ebp = 0 | |
192 | self.esp = 0 | |
193 | self.ss = 0 | |
194 | self.eflags = 0 | |
195 | self.eip = 0 | |
196 | self.cs = 0 | |
197 | self.ds = 0 | |
198 | self.es = 0 | |
199 | self.fs = 0 | |
200 | self.gs = 0 | |
201 | ||
202 | def __str__(self): | |
203 | return """ | |
204 | eax = {o.eax: #010x} | |
205 | ebx = {o.ebx: #010x} | |
206 | ecx = {o.ecx: #010x} | |
207 | edx = {o.edx: #010x} | |
208 | edi = {o.edi: #010x} | |
209 | esi = {o.esi: #010x} | |
210 | ebp = {o.ebp: #010x} | |
211 | esp = {o.esp: #010x} | |
212 | ss = {o.ss: #010x} | |
213 | eflags = {o.eflags: #010x} | |
214 | eip = {o.eip: #010x} | |
215 | cs = {o.cs: #010x} | |
216 | ds = {o.ds: #010x} | |
217 | es = {o.es: #010x} | |
218 | fs = {o.fs: #010x} | |
219 | gs = {o.gs: #010x} | |
220 | """.format(o=self) | |
221 | ||
222 | def GetPackedRegisterState(self): | |
223 | """ get a struct.pack register data """ | |
224 | return struct.pack('16I', self.eax, self.ebx, self.ecx, | |
225 | self.edx, self.edi, self.esi, | |
226 | self.ebp, self.esp, self.ss, | |
227 | self.eflags, self.eip, self.cs, | |
228 | self.ds, self.es, self.fs, self.gs | |
229 | ) | |
230 | def ReadRegisterDataFromKDPSavedState(self, kdp_state, kernel_version): | |
231 | """ to be implemented""" | |
232 | return None | |
233 | def ReadRegisterDataFromKernelStack(self, kstack_saved_state_addr, kernel_version): | |
234 | """ to be implemented """ | |
235 | return None | |
236 | ||
237 | def ReadRegisterDataFromContinuation(self, continuation_ptr): | |
238 | self.ResetRegisterValues() | |
239 | self.eip = continuation_ptr | |
240 | return self | |
241 | ||
242 | ||
243 | class X86_64RegisterSet(object): | |
244 | """ register info set for x86_64 architecture """ | |
245 | def __init__(self): | |
246 | self.register_info = {} | |
247 | self.register_info['sets'] = ['GPR', 'FPU', 'EXC'] | |
248 | self.register_info['registers'] = [ | |
249 | { 'name':'rax' , 'bitsize' : 64, 'offset' : 0, 'encoding':'uint' , 'format':'hex' , 'set': 0, 'gcc' : 0, 'dwarf' : 0}, | |
250 | { 'name':'rbx' , 'bitsize' : 64, 'offset' : 8, 'encoding':'uint' , 'format':'hex' , 'set': 0, 'gcc' : 3, 'dwarf' : 3}, | |
251 | { 'name':'rcx' , 'bitsize' : 64, 'offset' : 16, 'encoding':'uint' , 'format':'hex' , 'set': 0, 'gcc' : 2, 'dwarf' : 2, 'generic':'arg4', 'alt-name':'arg4', }, | |
252 | { 'name':'rdx' , 'bitsize' : 64, 'offset' : 24, 'encoding':'uint' , 'format':'hex' , 'set': 0, 'gcc' : 1, 'dwarf' : 1, 'generic':'arg3', 'alt-name':'arg3', }, | |
253 | { 'name':'rdi' , 'bitsize' : 64, 'offset' : 32, 'encoding':'uint' , 'format':'hex' , 'set': 0, 'gcc' : 5, 'dwarf' : 5, 'generic':'arg1', 'alt-name':'arg1', }, | |
254 | { 'name':'rsi' , 'bitsize' : 64, 'offset' : 40, 'encoding':'uint' , 'format':'hex' , 'set': 0, 'gcc' : 4, 'dwarf' : 4, 'generic':'arg2', 'alt-name':'arg2', }, | |
255 | { 'name':'rbp' , 'bitsize' : 64, 'offset' : 48, 'encoding':'uint' , 'format':'hex' , 'set': 0, 'gcc' : 6, 'dwarf' : 6, 'generic':'fp' , 'alt-name':'fp', }, | |
256 | { 'name':'rsp' , 'bitsize' : 64, 'offset' : 56, 'encoding':'uint' , 'format':'hex' , 'set': 0, 'gcc' : 7, 'dwarf' : 7, 'generic':'sp' , 'alt-name':'sp', }, | |
257 | { 'name':'r8' , 'bitsize' : 64, 'offset' : 64, 'encoding':'uint' , 'format':'hex' , 'set': 0, 'gcc' : 8, 'dwarf' : 8, 'generic':'arg5', 'alt-name':'arg5', }, | |
258 | { 'name':'r9' , 'bitsize' : 64, 'offset' : 72, 'encoding':'uint' , 'format':'hex' , 'set': 0, 'gcc' : 9, 'dwarf' : 9, 'generic':'arg6', 'alt-name':'arg6', }, | |
259 | { 'name':'r10' , 'bitsize' : 64, 'offset' : 80, 'encoding':'uint' , 'format':'hex' , 'set': 0, 'gcc' : 10, 'dwarf' : 10}, | |
260 | { 'name':'r11' , 'bitsize' : 64, 'offset' : 88, 'encoding':'uint' , 'format':'hex' , 'set': 0, 'gcc' : 11, 'dwarf' : 11}, | |
261 | { 'name':'r12' , 'bitsize' : 64, 'offset' : 96, 'encoding':'uint' , 'format':'hex' , 'set': 0, 'gcc' : 12, 'dwarf' : 12}, | |
262 | { 'name':'r13' , 'bitsize' : 64, 'offset' : 104, 'encoding':'uint' , 'format':'hex' , 'set': 0, 'gcc' : 13, 'dwarf' : 13}, | |
263 | { 'name':'r14' , 'bitsize' : 64, 'offset' : 112, 'encoding':'uint' , 'format':'hex' , 'set': 0, 'gcc' : 14, 'dwarf' : 14}, | |
264 | { 'name':'r15' , 'bitsize' : 64, 'offset' : 120, 'encoding':'uint' , 'format':'hex' , 'set': 0, 'gcc' : 15, 'dwarf' : 15}, | |
265 | { 'name':'rip' , 'bitsize' : 64, 'offset' : 128, 'encoding':'uint' , 'format':'hex' , 'set': 0, 'gcc' : 16, 'dwarf' : 16, 'generic':'pc', 'alt-name':'pc' }, | |
266 | { 'name':'rflags' , 'bitsize' : 64, 'offset' : 136, 'encoding':'uint' , 'format':'hex' , 'set': 0, 'generic':'flags', 'alt-name':'flags' }, | |
267 | { 'name':'cs' , 'bitsize' : 64, 'offset' : 144, 'encoding':'uint' , 'format':'hex' , 'set': 0 }, | |
268 | { 'name':'fs' , 'bitsize' : 64, 'offset' : 152, 'encoding':'uint' , 'format':'hex' , 'set': 0 }, | |
269 | { 'name':'gs' , 'bitsize' : 64, 'offset' : 160, 'encoding':'uint' , 'format':'hex' , 'set': 0 }, | |
270 | ] | |
271 | self.ResetRegisterValues() | |
272 | ||
273 | def ResetRegisterValues(self): | |
274 | """ set all the registers to zero. """ | |
275 | self.rax = 0 | |
276 | self.rbx = 0 | |
277 | self.rcx = 0 | |
278 | self.rdx = 0 | |
279 | self.rdi = 0 | |
280 | self.rsi = 0 | |
281 | self.rbp = 0 | |
282 | self.rsp = 0 | |
283 | self.r8 = 0 | |
284 | self.r9 = 0 | |
285 | self.r10 = 0 | |
286 | self.r11 = 0 | |
287 | self.r12 = 0 | |
288 | self.r13 = 0 | |
289 | self.r14 = 0 | |
290 | self.r15 = 0 | |
291 | self.rip = 0 | |
292 | self.rflags = 0 | |
293 | self.cs = 0 | |
294 | self.fs = 0 | |
295 | self.gs = 0 | |
296 | def __str__(self): | |
297 | return """ | |
298 | rax = {o.rax: <#018x} | |
299 | rbx = {o.rbx: <#018x} | |
300 | rcx = {o.rcx: <#018x} | |
301 | rdx = {o.rdx: <#018x} | |
302 | rdi = {o.rdi: <#018x} | |
303 | rsi = {o.rsi: <#018x} | |
304 | rbp = {o.rbp: <#018x} | |
305 | rsp = {o.rsp: <#018x} | |
306 | r8 = {o.r8: <#018x} | |
307 | r9 = {o.r9: <#018x} | |
308 | r10 = {o.r10: <#018x} | |
309 | r11 = {o.r11: <#018x} | |
310 | r12 = {o.r12: <#018x} | |
311 | r13 = {o.r13: <#018x} | |
312 | r14 = {o.r14: <#018x} | |
313 | r15 = {o.r15: <#018x} | |
314 | rip = {o.rip: <#018x} | |
315 | rflags = {o.rflags: <#018x} | |
316 | cs = {o.cs: <#018x} | |
317 | fs = {o.fs: <#018x} | |
318 | gs = {o.gs: <#018x} | |
319 | """.format(o=self) | |
320 | ||
321 | def GetPackedRegisterState(self): | |
322 | """ get a struct.pack register data for passing to C constructs """ | |
323 | return struct.pack('21Q', self.rax, self.rbx, self.rcx, self.rdx, self.rdi, | |
324 | self.rsi, self.rbp, self.rsp, self.r8, self.r9, | |
325 | self.r10, self.r11, self.r12, self.r13, self.r14, | |
326 | self.r15, self.rip, self.rflags, self.cs, self.fs, self.gs) | |
327 | ||
328 | def ReadRegisterDataFromKDPSavedState(self, kdp_state, kernel_version): | |
329 | saved_state = kernel_version.CreateValueFromExpression(None, '(struct x86_saved_state64 *) '+ str(kdp_state.GetValueAsUnsigned())) | |
330 | saved_state = saved_state.Dereference() | |
331 | saved_state = PluginValue(saved_state) | |
332 | self.ResetRegisterValues() | |
333 | self.rdi = saved_state.GetChildMemberWithName('rdi').GetValueAsUnsigned() | |
334 | self.rsi = saved_state.GetChildMemberWithName('rsi').GetValueAsUnsigned() | |
335 | self.rdx = saved_state.GetChildMemberWithName('rdx').GetValueAsUnsigned() | |
336 | self.r10 = saved_state.GetChildMemberWithName('r10').GetValueAsUnsigned() | |
337 | self.r8 = saved_state.GetChildMemberWithName('r8').GetValueAsUnsigned() | |
338 | self.r9 = saved_state.GetChildMemberWithName('r9').GetValueAsUnsigned() | |
339 | self.r15 = saved_state.GetChildMemberWithName('r15').GetValueAsUnsigned() | |
340 | self.r14 = saved_state.GetChildMemberWithName('r14').GetValueAsUnsigned() | |
341 | self.r13 = saved_state.GetChildMemberWithName('r13').GetValueAsUnsigned() | |
342 | self.r12 = saved_state.GetChildMemberWithName('r12').GetValueAsUnsigned() | |
343 | self.r11 = saved_state.GetChildMemberWithName('r11').GetValueAsUnsigned() | |
344 | self.rbp = saved_state.GetChildMemberWithName('rbp').GetValueAsUnsigned() | |
345 | self.rbx = saved_state.GetChildMemberWithName('rbx').GetValueAsUnsigned() | |
346 | self.rcx = saved_state.GetChildMemberWithName('rcx').GetValueAsUnsigned() | |
347 | self.rax = saved_state.GetChildMemberWithName('rax').GetValueAsUnsigned() | |
348 | self.rip = saved_state.GetChildMemberWithName('isf').GetChildMemberWithName('rip').GetValueAsUnsigned() | |
349 | self.rflags = saved_state.GetChildMemberWithName('isf').GetChildMemberWithName('rflags').GetValueAsUnsigned() | |
350 | self.rsp = saved_state.GetChildMemberWithName('isf').GetChildMemberWithName('rsp').GetValueAsUnsigned() | |
351 | return self | |
352 | ||
353 | def ReadRegisterDataFromKernelStack(self, kstack_saved_state_addr, kernel_version): | |
354 | saved_state = kernel_version.CreateValueFromExpression(None, '(struct x86_kernel_state *) '+ str(kstack_saved_state_addr)) | |
355 | saved_state = saved_state.Dereference() | |
356 | saved_state = PluginValue(saved_state) | |
357 | self.ResetRegisterValues() | |
358 | self.rbx = saved_state.GetChildMemberWithName('k_rbx').GetValueAsUnsigned() | |
359 | self.rsp = saved_state.GetChildMemberWithName('k_rsp').GetValueAsUnsigned() | |
360 | self.rbp = saved_state.GetChildMemberWithName('k_rbp').GetValueAsUnsigned() | |
361 | self.r12 = saved_state.GetChildMemberWithName('k_r12').GetValueAsUnsigned() | |
362 | self.r13 = saved_state.GetChildMemberWithName('k_r13').GetValueAsUnsigned() | |
363 | self.r14 = saved_state.GetChildMemberWithName('k_r14').GetValueAsUnsigned() | |
364 | self.r15 = saved_state.GetChildMemberWithName('k_r15').GetValueAsUnsigned() | |
365 | self.rip = saved_state.GetChildMemberWithName('k_rip').GetValueAsUnsigned() | |
366 | return self | |
367 | ||
368 | def ReadRegisterDataFromContinuation(self, continuation_ptr): | |
369 | self.ResetRegisterValues() | |
370 | self.rip = continuation_ptr | |
371 | return self | |
372 | ||
373 | ||
374 | ||
375 | ||
376 | def IterateQueue(queue_head, element_ptr_type, element_field_name): | |
377 | """ iterate over a queue in kernel of type queue_head_t. refer to osfmk/kern/queue.h | |
378 | params: | |
379 | queue_head - lldb.SBValue : Value object for queue_head. | |
380 | element_type - lldb.SBType : a pointer type of the element 'next' points to. Typically its structs like thread, task etc.. | |
381 | element_field_name - str : name of the field in target struct. | |
382 | returns: | |
383 | A generator does not return. It is used for iterating. | |
384 | SBValue : an object thats of type (element_type) queue_head->next. Always a pointer object | |
385 | """ | |
386 | queue_head_addr = 0x0 | |
387 | if queue_head.TypeIsPointerType(): | |
388 | queue_head_addr = queue_head.GetValueAsUnsigned() | |
389 | else: | |
390 | queue_head_addr = queue_head.GetAddress().GetLoadAddress(osplugin_target_obj) | |
391 | cur_elt = queue_head.GetChildMemberWithName('next') | |
392 | while True: | |
393 | ||
394 | if not cur_elt.IsValid() or cur_elt.GetValueAsUnsigned() == 0 or cur_elt.GetValueAsUnsigned() == queue_head_addr: | |
395 | break | |
396 | elt = cur_elt.Cast(element_ptr_type) | |
397 | yield elt | |
398 | cur_elt = elt.GetChildMemberWithName(element_field_name).GetChildMemberWithName('next') | |
399 | ||
400 | def GetUniqueSessionID(process_obj): | |
401 | """ Create a unique session identifier. | |
402 | params: | |
403 | process_obj: lldb.SBProcess object refering to connected process. | |
404 | returns: | |
405 | int - a unique number identified by processid and stopid. | |
406 | """ | |
407 | session_key_str = "" | |
408 | if hasattr(process_obj, "GetUniqueID"): | |
409 | session_key_str += str(process_obj.GetUniqueID()) + ":" | |
410 | else: | |
411 | session_key_str += "0:" | |
412 | ||
413 | if hasattr(process_obj, "GetStopID"): | |
414 | session_key_str += str(process_obj.GetStopID()) | |
415 | else: | |
416 | session_key_str +="1" | |
417 | ||
418 | return hash(session_key_str) | |
419 | ||
420 | ||
421 | (archX86_64, archARMv7_family, archI386) = ("x86_64", ("armv7", "armv7s") , "i386") | |
422 | ||
423 | class OperatingSystemPlugIn(object): | |
424 | """Class that provides data for an instance of a LLDB 'OperatingSystemPython' plug-in class""" | |
425 | ||
426 | def __init__(self, process): | |
427 | '''Initialization needs a valid.SBProcess object''' | |
428 | self.process = None | |
429 | self.registers = None | |
430 | self.threads = None | |
431 | self.thread_cache = {} | |
432 | self.current_session_id = 0 | |
433 | self.kdp_thread = None | |
434 | if type(process) is lldb.SBProcess and process.IsValid(): | |
435 | global osplugin_target_obj | |
436 | self.process = process | |
437 | self._target = process.target | |
438 | osplugin_target_obj = self._target | |
439 | self.current_session_id = GetUniqueSessionID(self.process) | |
440 | self.version = self._target.FindGlobalVariables('version', 0).GetValueAtIndex(0) | |
441 | self.kernel_stack_size = self._target.FindGlobalVariables('kernel_stack_size', 0).GetValueAtIndex(0).GetValueAsUnsigned() | |
442 | self.kernel_context_size = 0 | |
443 | self.connected_over_kdp = False | |
444 | plugin_string = self.process.GetPluginName().lower() | |
445 | if plugin_string.find("kdp") >=0: | |
446 | self.connected_over_kdp = True | |
447 | #print "version", self.version, "kernel_stack_size", self.kernel_stack_size, "context_size", self.kernel_context_size | |
448 | self.threads = None # Will be an dictionary containing info for each thread | |
449 | triple = self.process.target.triple | |
450 | arch = triple.split('-')[0].lower() | |
451 | self.target_arch = "" | |
452 | self.kernel_context_size = 0 | |
453 | if arch == archX86_64 : | |
454 | self.target_arch = archX86_64 | |
455 | print "Target arch: x86_64" | |
456 | self.register_set = X86_64RegisterSet() | |
457 | self.kernel_context_size = self._target.FindFirstType('x86_kernel_state').GetByteSize() | |
458 | elif arch in archARMv7_family : | |
459 | self.target_arch = arch | |
460 | print "Target arch: " + self.target_arch | |
461 | self.register_set = Armv7_RegisterSet() | |
462 | self.registers = self.register_set.register_info | |
463 | ||
464 | def create_thread(self, tid, context): | |
465 | th_ptr = context | |
466 | th = self.version.CreateValueFromExpression(str(th_ptr),'(struct thread *)' + str(th_ptr)) | |
467 | thread_id = th.GetChildMemberWithName('thread_id').GetValueAsUnsigned() | |
468 | if tid != thread_id: | |
469 | print "FATAL ERROR: Creating thread from memory 0x%x with tid in mem=%d when requested tid = %d " % (context, thread_id, tid) | |
470 | return None | |
471 | thread_obj = { 'tid' : thread_id, | |
472 | 'ptr' : th.GetValueAsUnsigned(), | |
473 | 'name' : hex(th.GetValueAsUnsigned()).rstrip('L'), | |
474 | 'queue' : hex(th.GetChildMemberWithName('wait_queue').GetValueAsUnsigned()).rstrip('L'), | |
475 | 'state' : 'stopped', | |
476 | 'stop_reason' : 'none' | |
477 | } | |
478 | if self.current_session_id != GetUniqueSessionID(self.process): | |
479 | self.thread_cache = {} | |
480 | self.current_session_id = GetUniqueSessionID(self.process) | |
481 | ||
482 | self.thread_cache[tid] = thread_obj | |
483 | return thread_obj | |
484 | ||
485 | ||
486 | def get_thread_info(self): | |
487 | self.kdp_thread = None | |
488 | self.kdp_state = None | |
489 | if self.connected_over_kdp : | |
490 | kdp = self._target.FindGlobalVariables('kdp',1).GetValueAtIndex(0) | |
491 | kdp_state = kdp.GetChildMemberWithName('saved_state') | |
492 | kdp_thread = kdp.GetChildMemberWithName('kdp_thread') | |
493 | if kdp_thread and kdp_thread.GetValueAsUnsigned() != 0: | |
494 | self.kdp_thread = kdp_thread | |
495 | self.kdp_state = kdp_state | |
496 | kdp_thid = kdp_thread.GetChildMemberWithName('thread_id').GetValueAsUnsigned() | |
497 | self.create_thread(kdp_thid, kdp_thread.GetValueAsUnsigned()) | |
498 | self.thread_cache[kdp_thid]['core']=0 | |
499 | retval = [self.thread_cache[kdp_thid]] | |
500 | return retval | |
501 | else: | |
502 | print "FATAL FAILURE: Unable to find kdp_thread state for this connection." | |
503 | return [] | |
504 | ||
505 | num_threads = self._target.FindGlobalVariables('threads_count',1).GetValueAtIndex(0).GetValueAsUnsigned() | |
506 | #In case we are caught before threads are initialized. Fallback to threads known by astris/gdb server. | |
507 | if num_threads <=0 : | |
508 | return [] | |
509 | ||
510 | self.current_session_id = GetUniqueSessionID(self.process) | |
511 | self.threads = [] | |
512 | self.thread_cache = {} | |
513 | self.processors = [] | |
514 | try: | |
515 | processor_list_val = PluginValue(self._target.FindGlobalVariables('processor_list',1).GetValueAtIndex(0)) | |
516 | while processor_list_val.IsValid() and processor_list_val.GetValueAsUnsigned() !=0 : | |
517 | th = processor_list_val.GetChildMemberWithName('active_thread') | |
518 | th_id = th.GetChildMemberWithName('thread_id').GetValueAsUnsigned() | |
519 | cpu_id = processor_list_val.GetChildMemberWithName('cpu_id').GetValueAsUnsigned() | |
520 | self.processors.append({'active_thread': th.GetValueAsUnsigned(), 'cpu_id': cpu_id}) | |
521 | self.create_thread(th_id, th.GetValueAsUnsigned()) | |
522 | self.thread_cache[th_id]['core'] = cpu_id | |
523 | nth = self.thread_cache[th_id] | |
524 | print "Found 0x%x on logical cpu %d" % ( nth['ptr'], nth['core']) | |
525 | self.threads.append(nth) | |
526 | self.thread_cache[nth['tid']] = nth | |
527 | processor_list_val = processor_list_val.GetChildMemberWithName('processor_list') | |
528 | except KeyboardInterrupt, ke: | |
529 | print "OS Plugin Interrupted during thread loading process. \nWARNING:Thread registers and backtraces may not be accurate." | |
530 | return self.threads | |
531 | ||
532 | if hasattr(self.process, 'CreateOSPluginThread'): | |
533 | return self.threads | |
534 | ||
535 | # FIXME remove legacy code | |
536 | try: | |
537 | thread_q_head = self._target.FindGlobalVariables('threads', 0).GetValueAtIndex(0) | |
538 | thread_type = self._target.FindFirstType('thread') | |
539 | thread_ptr_type = thread_type.GetPointerType() | |
540 | for th in IterateQueue(thread_q_head, thread_ptr_type, 'threads'): | |
541 | th_id = th.GetChildMemberWithName('thread_id').GetValueAsUnsigned() | |
542 | self.create_thread(th_id, th.GetValueAsUnsigned()) | |
543 | nth = self.thread_cache[th_id] | |
544 | for cputhread in self.processors: | |
545 | if cputhread['active_thread'] == nth['ptr']: | |
546 | nth['core'] = cputhread['cpu_id'] | |
547 | #print "Found 0x%x on logical cpu %d" % ( nth['ptr'], cputhread['cpu_id']) | |
548 | self.threads.append( nth ) | |
549 | except KeyboardInterrupt, ke: | |
550 | print "OS Plugin Interrupted during thread loading process. \nWARNING:Thread registers and backtraces may not be accurate." | |
551 | return self.threads | |
552 | # end legacy code | |
553 | return self.threads | |
554 | ||
555 | def get_register_info(self): | |
556 | if self.registers == None: | |
557 | print "Register Information not found " | |
558 | return self.register_set.register_info | |
559 | ||
560 | def get_register_data(self, tid): | |
561 | #print "searching for tid", tid | |
562 | thobj = None | |
563 | try: | |
564 | if self.current_session_id != GetUniqueSessionID(self.process): | |
565 | self.thread_cache = {} | |
566 | self.current_session_id = GetUniqueSessionID(self.process) | |
567 | ||
568 | if tid in self.thread_cache.keys(): | |
569 | thobj = self.version.CreateValueFromExpression(self.thread_cache[tid]['name'], '(struct thread *)' + str(self.thread_cache[tid]['ptr'])) | |
570 | regs = self.register_set | |
571 | if thobj == None : | |
572 | print "FATAL ERROR: Could not find thread with id %d" % tid | |
573 | regs.ResetRegisterValues() | |
574 | return regs.GetPackedRegisterState() | |
575 | ||
576 | if self.kdp_thread and self.kdp_thread.GetValueAsUnsigned() == thobj.GetValueAsUnsigned(): | |
577 | regs.ReadRegisterDataFromKDPSavedState(self.kdp_state, self.version) | |
578 | return regs.GetPackedRegisterState() | |
579 | if int(PluginValue(thobj).GetChildMemberWithName('kernel_stack').GetValueAsUnsigned()) != 0 : | |
580 | if self.target_arch == archX86_64 : | |
581 | # we do have a stack so lets get register information | |
582 | saved_state_addr = PluginValue(thobj).GetChildMemberWithName('kernel_stack').GetValueAsUnsigned() + self.kernel_stack_size - self.kernel_context_size | |
583 | regs.ReadRegisterDataFromKernelStack(saved_state_addr, self.version) | |
584 | return regs.GetPackedRegisterState() | |
585 | elif self.target_arch in archARMv7_family and int(PluginValue(thobj).GetChildMemberWithName('machine').GetChildMemberWithName('kstackptr').GetValueAsUnsigned()) != 0: | |
586 | #we have stack on the machine.kstackptr. | |
587 | saved_state_addr = PluginValue(thobj).GetChildMemberWithName('machine').GetChildMemberWithName('kstackptr').GetValueAsUnsigned() | |
588 | regs.ReadRegisterDataFromKernelStack(saved_state_addr, self.version) | |
589 | return regs.GetPackedRegisterState() | |
590 | elif self.target_arch == archX86_64 or self.target_arch in archARMv7_family: | |
591 | regs.ReadRegisterDataFromContinuation( PluginValue(thobj).GetChildMemberWithName('continuation').GetValueAsUnsigned()) | |
592 | return regs.GetPackedRegisterState() | |
593 | #incase we failed very miserably | |
594 | except KeyboardInterrupt, ke: | |
595 | print "OS Plugin Interrupted during thread register load. \nWARNING:Thread registers and backtraces may not be accurate. for tid = %d" % tid | |
596 | regs.ResetRegisterValues() | |
597 | print "FATAL ERROR: Failed to get register state for thread id 0x%x " % tid | |
598 | print thobj | |
599 | return regs.GetPackedRegisterState() | |
600 |