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