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