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