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