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