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