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