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