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