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