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