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