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