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