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