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