]> git.saurik.com Git - apple/xnu.git/blob - tools/lldbmacros/usertaskdebugging/userprocess.py
xnu-6153.61.1.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 CPU_TYPE_ARM64_32 = 0x0200000c
14
15 def GetRegisterSetForCPU(cputype, subtype):
16 if cputype == CPU_TYPE_ARM64:
17 retval = Armv8_RegisterSet
18 elif cputype == CPU_TYPE_ARM64_32:
19 retval = Armv8_RegisterSet
20 elif cputype == CPU_TYPE_ARM:
21 retval = Armv7_RegisterSet
22 elif cputype == CPU_TYPE_I386:
23 retval = I386_RegisterSet
24 elif cputype == CPU_TYPE_X86_64:
25 retval = X86_64RegisterSet
26
27 """ crash if unknown cputype """
28
29 return retval.register_info['registers']
30
31
32 class UserThreadObject(object):
33 """representation of userspace thread"""
34 def __init__(self, thr_obj, cputype, cpusubtype, is_kern_64bit):
35 super(UserThreadObject, self).__init__()
36 self.thread = thr_obj
37 self.registerset = GetRegisterSetForCPU(cputype, cpusubtype)
38 self.thread_id = unsigned(self.thread.thread_id)
39 self.is64Bit = bool(cputype & 0x01000000)
40
41 if self.is64Bit:
42 if cputype == CPU_TYPE_X86_64:
43 self.reg_type = "x86_64"
44 self.saved_state = Cast(self.thread.machine.iss, 'x86_saved_state_t *').uss.ss_64
45 if cputype == CPU_TYPE_ARM64:
46 self.reg_type = "arm64"
47 self.saved_state = self.thread.machine.upcb.uss.ss_64
48 else:
49 if cputype == CPU_TYPE_I386:
50 self.reg_type = "i386"
51 self.saved_state = Cast(self.thread.machine.iss, 'x86_saved_state_t *').uss.ss_32
52 if cputype == CPU_TYPE_ARM:
53 self.reg_type = "arm"
54 if not is_kern_64bit:
55 self.saved_state = self.thread.machine.PcbData
56 else:
57 self.saved_state = self.thread.machine.contextData.ss.uss.ss_32
58 if cputype == CPU_TYPE_ARM64_32:
59 self.reg_type = "arm64"
60 self.saved_state = self.thread.machine.upcb.uss.ss_64
61
62 logging.debug("created thread id 0x%x of type %s, is_kern_64bit 0x%x cputype 0x%x"
63 % (self.thread_id, self.reg_type, is_kern_64bit, 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 = True
109
110 is_kern_64bit = kern.arch in ['x86_64', 'x86_64h', 'arm64', 'arm64e']
111
112 self.cputype = unsigned(self.proc.p_cputype)
113 self.cpusubtype = unsigned(self.proc.p_cpusubtype)
114
115 super(UserProcess, self).__init__(self.cputype, self.cpusubtype, ptrsize)
116
117 self.hinfo['ostype'] = 'macosx'
118 if self.cputype != CPU_TYPE_X86_64 and self.cputype != CPU_TYPE_I386:
119 self.hinfo['ostype'] = 'ios'
120
121 self.registerset = GetRegisterSetForCPU(self.cputype, self.cpusubtype)
122 logging.debug("process %s is64bit: %d ptrsize: %d cputype: %d cpusubtype:%d",
123 hex(self.proc), int(dataregisters64bit), ptrsize,
124 self.cputype, self.cpusubtype
125 )
126 self.threads = {}
127 self.threads_ids_list = []
128 logging.debug("iterating over threads in process")
129 for thval in IterateQueue(task.threads, 'thread *', 'task_threads'):
130 self.threads[unsigned(thval.thread_id)] = UserThreadObject(thval, self.cputype, self.cpusubtype, is_kern_64bit)
131 self.threads_ids_list.append(unsigned(thval.thread_id))
132
133 def getRegisterDataForThread(self, th_id, reg_num):
134 if th_id not in self.threads:
135 logging.critical("0x%x thread id is not found in this task")
136 return ''
137 if reg_num < 0 or reg_num >= len(self.registerset):
138 logging.warning("regnum %d is not defined for thread_id 0x%x" % (reg_num, th_id))
139 return ''
140 value = self.threads[th_id].getRegisterData(reg_num)
141 return self.encodeRegisterData(value, bytesize=self.registerset[reg_num]['bitsize']/8)
142
143 def getRegisterCombinedDataForThread(self, th_id):
144 if th_id not in self.threads:
145 logging.critical("0x%x thread id is not found in this task" % th_id)
146 return ''
147 cur_thread = self.threads[th_id]
148 retval = 'thread:%s;name:%s;' % (self.encodeThreadID(th_id), cur_thread.getName())
149 pos = 0
150 for rinfo in self.registerset:
151 name = rinfo['name']
152 format = "%02x:%s;"
153 value = cur_thread.getRegisterValueByName(name)
154 value_endian_correct_str = self.encodeRegisterData(value, bytesize=(rinfo['bitsize']/8))
155 retval += format % (pos, value_endian_correct_str)
156 pos += 1
157 return retval
158
159 def getThreadStopInfo(self, th_id):
160 if th_id not in self.threads:
161 logging.critical("0x%x thread id is not found in this task")
162 return ''
163 return 'T02' + self.getRegisterCombinedDataForThread(th_id) + 'threads:' + self.getThreadsInfo()+';'
164
165 def getRegisterInfo(self, regnum):
166 #something similar to
167 #"name:x1;bitsize:64;offset:8;encoding:uint;format:hex;gcc:1;dwarf:1;set:General Purpose Registers;"
168 if regnum > len(self.registerset):
169 logging.debug("No register_info for number %d." % regnum)
170 return 'E45'
171
172 rinfo = self.registerset[regnum]
173 retval = ''
174 for i in rinfo.keys():
175 i_val = str(rinfo[i])
176 if i == 'set':
177 i_val = 'General Purpose Registers'
178 retval += '%s:%s;' % (str(i), i_val)
179
180 return retval
181
182 def getProcessInfo(self):
183 retval = ''
184 #pid:d22c;parent-pid:d34d;real-uid:ecf;real-gid:b;effective-uid:ecf;effective-gid:b;cputype:1000007;cpusubtype:3;
185 #ostype:macosx;vendor:apple;endian:little;ptrsize:8;
186 pinfo = {'effective-uid': 'ecf', 'effective-gid': 'b', 'endian': 'little', 'vendor': 'apple'}
187 pinfo['pid'] = "%x" % (GetProcPIDForTask(self.task))
188 pinfo['parent-pid'] = "%x" % (unsigned(self.proc.p_ppid))
189 pinfo['ptrsize'] = str(self.ptrsize)
190 pinfo['ostype'] = 'macosx'
191 pinfo['cputype'] = "%x" % self.cputype
192 pinfo['cpusubtype'] = "%x" % self.cpusubtype
193 pinfo['real-uid'] = "%x" % (unsigned(self.proc.p_ruid))
194 pinfo['real-gid'] = "%x" % (unsigned(self.proc.p_rgid))
195 if str(kern.arch).find('arm') >= 0:
196 pinfo['ostype'] = 'ios'
197 for i in pinfo.keys():
198 i_val = str(pinfo[i])
199 retval += '%s:%s;' % (str(i), i_val)
200 return retval
201
202 def readMemory(self, address, size):
203 data = GetUserDataAsString(self.task, address, size)
204 if not data:
205 logging.error("Failed to read memory task:{: <#018x} {: <#018x} {:d}".format(self.task, address, size))
206 return self.encodeByteString(data)
207
208 def getSharedLibInfoAddress(self):
209 return unsigned(self.task.all_image_info_addr)