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