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