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