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