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