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