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