]> git.saurik.com Git - apple/xnu.git/blob - tools/lldbmacros/usertaskdebugging/userprocess.py
xnu-4570.1.46.tar.gz
[apple/xnu.git] / tools / lldbmacros / usertaskdebugging / userprocess.py
1 import logging
2 import target
3 import struct
4
5 from xnu import *
6 from core.operating_system import Armv8_RegisterSet, Armv7_RegisterSet, I386_RegisterSet, X86_64RegisterSet
7
8 """ these defines should come from an authoritative header file """
9 CPU_TYPE_I386 = 0x00000007
10 CPU_TYPE_X86_64 = 0x01000007
11 CPU_TYPE_ARM = 0x0000000c
12 CPU_TYPE_ARM64 = 0x0100000c
13
14
15 CPU_SUBTYPE_X86_64_ALL = 3
16 CPU_SUBTYPE_X86_64_H = 8
17 CPU_SUBTYPE_ARMV8 = 13
18 CPU_SUBTYPE_ARM_V7 = 9
19 CPU_SUBTYPE_ARM_V7S = 11
20 CPU_SUBTYPE_ARM_V7K = 12
21
22
23 def GetRegisterSetForCPU(cputype, subtype):
24 if cputype == CPU_TYPE_ARM64:
25 retval = Armv8_RegisterSet
26 elif cputype == CPU_TYPE_ARM:
27 retval = Armv7_RegisterSet
28 elif cputype == CPU_TYPE_I386:
29 retval = I386_RegisterSet
30 elif cputype == CPU_TYPE_X86_64:
31 retval = X86_64RegisterSet
32
33 """ crash if unknown cputype """
34
35 return retval.register_info['registers']
36
37
38 class UserThreadObject(object):
39 """representation of userspace thread"""
40 def __init__(self, thr_obj, cputype, cpusubtype, kern_cputype):
41 super(UserThreadObject, self).__init__()
42 self.thread = thr_obj
43 self.registerset = GetRegisterSetForCPU(cputype, cpusubtype)
44 self.thread_id = unsigned(self.thread.thread_id)
45 self.is64Bit = bool(cputype & 0x01000000)
46 isKern64Bit = bool(kern_cputype & 0x01000000)
47
48 if self.is64Bit:
49 if cputype == CPU_TYPE_X86_64:
50 self.reg_type = "x86_64"
51 self.saved_state = Cast(self.thread.machine.iss, 'x86_saved_state_t *').uss.ss_64
52 if cputype == CPU_TYPE_ARM64:
53 self.reg_type = "arm64"
54 self.saved_state = self.thread.machine.upcb.uss.ss_64
55 else:
56 if cputype == CPU_TYPE_I386:
57 self.reg_type = "i386"
58 self.saved_state = Cast(self.thread.machine.iss, 'x86_saved_state_t *').uss.ss_32
59 if cputype == CPU_TYPE_ARM:
60 self.reg_type = "arm"
61 if not isKern64Bit:
62 self.saved_state = self.thread.machine.PcbData
63 else:
64 self.saved_state = self.thread.machine.contextData.ss.uss.ss_32
65 logging.debug("created thread id 0x%x of type %s, kern_cputype 0x%x cputype 0x%x"
66 % (self.thread_id, self.reg_type, kern_cputype, cputype))
67
68 def getRegisterValueByName(self, name):
69 if self.reg_type == 'arm64':
70 if name in ('x0', 'x1', 'x2', 'x3', 'x4', 'x5', 'x6', 'x7', 'x8', 'x9', 'x10', 'x11', 'x12', 'x13', 'x14', 'x15', 'x16', 'x17', 'x18', 'x19', 'x20', 'x21', 'x22', 'x23', 'x24', 'x25', 'x26', 'x27', 'x28'):
71 return unsigned(getattr(self.saved_state, 'x')[int(name.strip('x'))])
72
73 return unsigned(getattr(self.saved_state, name))
74
75 if self.reg_type == "x86_64":
76 if name in ('rip', 'rflags', 'cs', 'rsp', 'cpu'):
77 return unsigned(getattr(self.saved_state.isf, name))
78 return unsigned(getattr(self.saved_state, name))
79
80 if self.reg_type == "arm":
81 if name in ('r0', 'r1', 'r2', 'r3', 'r4', 'r5', 'r6', 'r7', 'r8', 'r9', 'r10', 'r11', 'r12'):
82 retval = unsigned(getattr(self.saved_state, 'r')[int(name.strip('r'))])
83 else:
84 retval = unsigned(getattr(self.saved_state, name))
85 return retval
86
87 #TODO for i386
88
89 def getName(self):
90 return str(self.thread_id)
91
92 def getRegisterData(self, reg_num):
93 """ returns None if there is error """
94 if reg_num < 0 or reg_num >= len(self.registerset):
95 logging.warning("regnum %d is not defined for thread_id 0x%x" % (reg_num, self.thread_id))
96 return None
97 return self.getRegisterValueByName(self.registerset[reg_num]['name'])
98
99
100 class UserProcess(target.Process):
101 """ Represent a user process and thread states """
102 def __init__(self, task):
103 self.task = task
104 self.proc = Cast(task.bsd_info, 'proc_t')
105 dataregisters64bit = False
106 ptrsize = 4
107
108 if task.t_flags & 0x1:
109 ptrsize = 8
110 if task.t_flags & 0x2:
111 dataregisters64bit = 8
112
113 cputype = CPU_TYPE_X86_64
114 cpusubtype = CPU_SUBTYPE_X86_64_ALL
115
116
117 """ these computations should come out of the macho header i think """
118 """ where does kern.arch come from? what's kern.arch == armv8?? """
119 if kern.arch in ('arm'):
120 cputype = CPU_TYPE_ARM
121 cpusubtype = CPU_SUBTYPE_ARM_V7
122 elif kern.arch in ('armv8', 'arm64'):
123 cputype = CPU_TYPE_ARM64
124 cpusubtype = CPU_SUBTYPE_ARMV8
125
126 super(UserProcess, self).__init__(cputype, cpusubtype, ptrsize)
127
128 self.hinfo['ostype'] = 'macosx'
129 if cputype != CPU_TYPE_X86_64:
130 self.hinfo['ostype'] = 'ios'
131
132 self.cputype = unsigned(self.proc.p_cputype)
133 self.cpusubtype = unsigned(self.proc.p_cpusubtype)
134 self.registerset = GetRegisterSetForCPU(cputype, cpusubtype)
135 logging.debug("process %s is64bit: %d ptrsize: %d cputype: %d cpusubtype:%d",
136 hex(self.proc), int(dataregisters64bit), ptrsize,
137 self.cputype, self.cpusubtype
138 )
139 self.threads = {}
140 self.threads_ids_list = []
141 logging.debug("iterating over threads in process")
142 for thval in IterateQueue(task.threads, 'thread *', 'task_threads'):
143 self.threads[unsigned(thval.thread_id)] = UserThreadObject(thval, self.cputype, self.cpusubtype, cputype)
144 self.threads_ids_list.append(unsigned(thval.thread_id))
145
146 def getRegisterDataForThread(self, th_id, reg_num):
147 if th_id not in self.threads:
148 logging.critical("0x%x thread id is not found in this task")
149 return ''
150 if reg_num < 0 or reg_num >= len(self.registerset):
151 logging.warning("regnum %d is not defined for thread_id 0x%x" % (reg_num, th_id))
152 return ''
153 value = self.threads[th_id].getRegisterData(reg_num)
154 return self.encodeRegisterData(value, bytesize=self.registerset[reg_num]['bitsize']/8)
155
156 def getRegisterCombinedDataForThread(self, th_id):
157 if th_id not in self.threads:
158 logging.critical("0x%x thread id is not found in this task" % th_id)
159 return ''
160 cur_thread = self.threads[th_id]
161 retval = 'thread:%s;name:%s;' % (self.encodeThreadID(th_id), cur_thread.getName())
162 pos = 0
163 for rinfo in self.registerset:
164 name = rinfo['name']
165 format = "%02x:%s;"
166 value = cur_thread.getRegisterValueByName(name)
167 value_endian_correct_str = self.encodeRegisterData(value, bytesize=(rinfo['bitsize']/8))
168 retval += format % (pos, value_endian_correct_str)
169 pos += 1
170 return retval
171
172 def getThreadStopInfo(self, th_id):
173 if th_id not in self.threads:
174 logging.critical("0x%x thread id is not found in this task")
175 return ''
176 return 'T02' + self.getRegisterCombinedDataForThread(th_id) + 'threads:' + self.getThreadsInfo()+';'
177
178 def getRegisterInfo(self, regnum):
179 #something similar to
180 #"name:x1;bitsize:64;offset:8;encoding:uint;format:hex;gcc:1;dwarf:1;set:General Purpose Registers;"
181 if regnum > len(self.registerset):
182 logging.debug("No register_info for number %d." % regnum)
183 return 'E45'
184
185 rinfo = self.registerset[regnum]
186 retval = ''
187 for i in rinfo.keys():
188 i_val = str(rinfo[i])
189 if i == 'set':
190 i_val = 'General Purpose Registers'
191 retval += '%s:%s;' % (str(i), i_val)
192
193 return retval
194
195 def getProcessInfo(self):
196 retval = ''
197 #pid:d22c;parent-pid:d34d;real-uid:ecf;real-gid:b;effective-uid:ecf;effective-gid:b;cputype:1000007;cpusubtype:3;
198 #ostype:macosx;vendor:apple;endian:little;ptrsize:8;
199 pinfo = {'effective-uid': 'ecf', 'effective-gid': 'b', 'endian': 'little', 'vendor': 'apple'}
200 pinfo['pid'] = "%x" % (GetProcPIDForTask(self.task))
201 pinfo['parent-pid'] = "%x" % (unsigned(self.proc.p_ppid))
202 pinfo['ptrsize'] = str(self.ptrsize)
203 pinfo['ostype'] = 'macosx'
204 pinfo['cputype'] = "%x" % self.cputype
205 pinfo['cpusubtype'] = "%x" % self.cpusubtype
206 pinfo['real-uid'] = "%x" % (unsigned(self.proc.p_ruid))
207 pinfo['real-gid'] = "%x" % (unsigned(self.proc.p_rgid))
208 if str(kern.arch).find('arm') >= 0:
209 pinfo['ostype'] = 'ios'
210 for i in pinfo.keys():
211 i_val = str(pinfo[i])
212 retval += '%s:%s;' % (str(i), i_val)
213 return retval
214
215 def readMemory(self, address, size):
216 data = GetUserDataAsString(self.task, address, size)
217 if not data:
218 logging.error("Failed to read memory task:{: <#018x} {: <#018x} {:d}".format(self.task, address, size))
219 return self.encodeByteString(data)
220
221 def getSharedLibInfoAddress(self):
222 return unsigned(self.task.all_image_info_addr)