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