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