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