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