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