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