6 from core
.operating_system
import Armv8_RegisterSet
, Armv7_RegisterSet
, I386_RegisterSet
, X86_64RegisterSet
8 """ these defines should come from an authoritative header file """
9 CPU_TYPE_I386
= 0x00000007
10 CPU_TYPE_X86_64
= 0x01000007
11 CPU_TYPE_ARM
= 0x0000000c
12 CPU_TYPE_ARM64
= 0x0100000c
13 CPU_TYPE_ARM64_32
= 0x0200000c
15 def GetRegisterSetForCPU(cputype
, subtype
):
16 if cputype
== CPU_TYPE_ARM64
:
17 retval
= Armv8_RegisterSet
18 elif cputype
== CPU_TYPE_ARM64_32
:
19 retval
= Armv8_RegisterSet
20 elif cputype
== CPU_TYPE_ARM
:
21 retval
= Armv7_RegisterSet
22 elif cputype
== CPU_TYPE_I386
:
23 retval
= I386_RegisterSet
24 elif cputype
== CPU_TYPE_X86_64
:
25 retval
= X86_64RegisterSet
27 """ crash if unknown cputype """
29 return retval
.register_info
['registers']
32 class UserThreadObject(object):
33 """representation of userspace thread"""
34 def __init__(self
, thr_obj
, cputype
, cpusubtype
, is_kern_64bit
):
35 super(UserThreadObject
, self
).__init
__()
37 self
.registerset
= GetRegisterSetForCPU(cputype
, cpusubtype
)
38 self
.thread_id
= unsigned(self
.thread
.thread_id
)
39 self
.is64Bit
= bool(cputype
& 0x01000000)
42 if cputype
== CPU_TYPE_X86_64
:
43 self
.reg_type
= "x86_64"
44 self
.saved_state
= Cast(self
.thread
.machine
.iss
, 'x86_saved_state_t *').uss
.ss_64
45 if cputype
== CPU_TYPE_ARM64
:
46 self
.reg_type
= "arm64"
47 self
.saved_state
= self
.thread
.machine
.upcb
.uss
.ss_64
49 if cputype
== CPU_TYPE_I386
:
50 self
.reg_type
= "i386"
51 self
.saved_state
= Cast(self
.thread
.machine
.iss
, 'x86_saved_state_t *').uss
.ss_32
52 if cputype
== CPU_TYPE_ARM
:
55 self
.saved_state
= self
.thread
.machine
.PcbData
57 self
.saved_state
= self
.thread
.machine
.contextData
.ss
.uss
.ss_32
58 if cputype
== CPU_TYPE_ARM64_32
:
59 self
.reg_type
= "arm64"
60 self
.saved_state
= self
.thread
.machine
.upcb
.uss
.ss_64
62 logging
.debug("created thread id 0x%x of type %s, is_kern_64bit 0x%x cputype 0x%x"
63 % (self
.thread_id
, self
.reg_type
, is_kern_64bit
, cputype
))
65 def getRegisterValueByName(self
, name
):
66 if self
.reg_type
== 'arm64':
67 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'):
68 return unsigned(getattr(self
.saved_state
, 'x')[int(name
.strip('x'))])
70 return unsigned(getattr(self
.saved_state
, name
))
72 if self
.reg_type
== "x86_64":
73 if name
in ('rip', 'rflags', 'cs', 'rsp', 'cpu'):
74 return unsigned(getattr(self
.saved_state
.isf
, name
))
75 return unsigned(getattr(self
.saved_state
, name
))
77 if self
.reg_type
== "arm":
78 if name
in ('r0', 'r1', 'r2', 'r3', 'r4', 'r5', 'r6', 'r7', 'r8', 'r9', 'r10', 'r11', 'r12'):
79 retval
= unsigned(getattr(self
.saved_state
, 'r')[int(name
.strip('r'))])
81 retval
= unsigned(getattr(self
.saved_state
, name
))
87 return str(self
.thread_id
)
89 def getRegisterData(self
, reg_num
):
90 """ returns None if there is error """
91 if reg_num
< 0 or reg_num
>= len(self
.registerset
):
92 logging
.warning("regnum %d is not defined for thread_id 0x%x" % (reg_num
, self
.thread_id
))
94 return self
.getRegisterValueByName(self
.registerset
[reg_num
]['name'])
97 class UserProcess(target
.Process
):
98 """ Represent a user process and thread states """
99 def __init__(self
, task
):
101 self
.proc
= Cast(task
.bsd_info
, 'proc_t')
102 dataregisters64bit
= False
105 if task
.t_flags
& 0x1:
107 if task
.t_flags
& 0x2:
108 dataregisters64bit
= True
110 is_kern_64bit
= kern
.arch
in ['x86_64', 'x86_64h', 'arm64', 'arm64e']
112 self
.cputype
= unsigned(self
.proc
.p_cputype
)
113 self
.cpusubtype
= unsigned(self
.proc
.p_cpusubtype
)
115 super(UserProcess
, self
).__init
__(self
.cputype
, self
.cpusubtype
, ptrsize
)
117 self
.hinfo
['ostype'] = 'macosx'
118 if self
.cputype
!= CPU_TYPE_X86_64
and self
.cputype
!= CPU_TYPE_I386
:
119 self
.hinfo
['ostype'] = 'ios'
121 self
.registerset
= GetRegisterSetForCPU(self
.cputype
, self
.cpusubtype
)
122 logging
.debug("process %s is64bit: %d ptrsize: %d cputype: %d cpusubtype:%d",
123 hex(self
.proc
), int(dataregisters64bit
), ptrsize
,
124 self
.cputype
, self
.cpusubtype
127 self
.threads_ids_list
= []
128 logging
.debug("iterating over threads in process")
129 for thval
in IterateQueue(task
.threads
, 'thread *', 'task_threads'):
130 self
.threads
[unsigned(thval
.thread_id
)] = UserThreadObject(thval
, self
.cputype
, self
.cpusubtype
, is_kern_64bit
)
131 self
.threads_ids_list
.append(unsigned(thval
.thread_id
))
133 def getRegisterDataForThread(self
, th_id
, reg_num
):
134 if th_id
not in self
.threads
:
135 logging
.critical("0x%x thread id is not found in this task")
137 if reg_num
< 0 or reg_num
>= len(self
.registerset
):
138 logging
.warning("regnum %d is not defined for thread_id 0x%x" % (reg_num
, th_id
))
140 value
= self
.threads
[th_id
].getRegisterData(reg_num
)
141 return self
.encodeRegisterData(value
, bytesize
=self
.registerset
[reg_num
]['bitsize']/8)
143 def getRegisterCombinedDataForThread(self
, th_id
):
144 if th_id
not in self
.threads
:
145 logging
.critical("0x%x thread id is not found in this task" % th_id
)
147 cur_thread
= self
.threads
[th_id
]
148 retval
= 'thread:%s;name:%s;' % (self
.encodeThreadID(th_id
), cur_thread
.getName())
150 for rinfo
in self
.registerset
:
153 value
= cur_thread
.getRegisterValueByName(name
)
154 value_endian_correct_str
= self
.encodeRegisterData(value
, bytesize
=(rinfo
['bitsize']/8))
155 retval
+= format
% (pos
, value_endian_correct_str
)
159 def getThreadStopInfo(self
, th_id
):
160 if th_id
not in self
.threads
:
161 logging
.critical("0x%x thread id is not found in this task")
163 return 'T02' + self
.getRegisterCombinedDataForThread(th_id
) + 'threads:' + self
.getThreadsInfo()+';'
165 def getRegisterInfo(self
, regnum
):
166 #something similar to
167 #"name:x1;bitsize:64;offset:8;encoding:uint;format:hex;gcc:1;dwarf:1;set:General Purpose Registers;"
168 if regnum
> len(self
.registerset
):
169 logging
.debug("No register_info for number %d." % regnum
)
172 rinfo
= self
.registerset
[regnum
]
174 for i
in rinfo
.keys():
175 i_val
= str(rinfo
[i
])
177 i_val
= 'General Purpose Registers'
178 retval
+= '%s:%s;' % (str(i
), i_val
)
182 def getProcessInfo(self
):
184 #pid:d22c;parent-pid:d34d;real-uid:ecf;real-gid:b;effective-uid:ecf;effective-gid:b;cputype:1000007;cpusubtype:3;
185 #ostype:macosx;vendor:apple;endian:little;ptrsize:8;
186 pinfo
= {'effective-uid': 'ecf', 'effective-gid': 'b', 'endian': 'little', 'vendor': 'apple'}
187 pinfo
['pid'] = "%x" % (GetProcPIDForTask(self
.task
))
188 pinfo
['parent-pid'] = "%x" % (unsigned(self
.proc
.p_ppid
))
189 pinfo
['ptrsize'] = str(self
.ptrsize
)
190 pinfo
['ostype'] = 'macosx'
191 pinfo
['cputype'] = "%x" % self
.cputype
192 pinfo
['cpusubtype'] = "%x" % self
.cpusubtype
193 pinfo
['real-uid'] = "%x" % (unsigned(self
.proc
.p_ruid
))
194 pinfo
['real-gid'] = "%x" % (unsigned(self
.proc
.p_rgid
))
195 if str(kern
.arch
).find('arm') >= 0:
196 pinfo
['ostype'] = 'ios'
197 for i
in pinfo
.keys():
198 i_val
= str(pinfo
[i
])
199 retval
+= '%s:%s;' % (str(i
), i_val
)
202 def readMemory(self
, address
, size
):
203 data
= GetUserDataAsString(self
.task
, address
, size
)
205 logging
.error("Failed to read memory task:{: <#018x} {: <#018x} {:d}".format(self
.task
, address
, size
))
206 return self
.encodeByteString(data
)
208 def getSharedLibInfoAddress(self
):
209 return unsigned(self
.task
.all_image_info_addr
)