Package vtrace :: Package platforms :: Package darwin
[hide private]
[frames] | no frames]

Source Code for Package vtrace.platforms.darwin

  1  """ 
  2  Darwin Platform Module 
  3  """ 
  4  # Copyright (C) 2007 Invisigoth - See LICENSE file for details 
  5  import os 
  6  import struct 
  7  import ctypes 
  8  import signal 
  9  import ctypes.util as c_util 
 10   
 11  import envi.memory as e_mem 
 12   
 13  import vtrace 
 14  import vtrace.archs.i386 as v_i386 
 15  import vtrace.archs.amd64 as v_amd64 
 16  import vtrace.platforms.base as v_base 
 17  import vtrace.platforms.posix as v_posix 
 18   
 19  addrof = ctypes.pointer 
 20   
 21  # The OSX ptrace defines... 
 22  PT_TRACE_ME     = 0    # child declares it's being traced 
 23  PT_READ_I       = 1    # read word in child's I space 
 24  PT_READ_D       = 2    # read word in child's D space 
 25  PT_READ_U       = 3    # read word in child's user structure 
 26  PT_WRITE_I      = 4    # write word in child's I space 
 27  PT_WRITE_D      = 5    # write word in child's D space 
 28  PT_WRITE_U      = 6    # write word in child's user structure 
 29  PT_CONTINUE     = 7    # continue the child 
 30  PT_KILL         = 8    # kill the child process 
 31  PT_STEP         = 9    # single step the child 
 32  PT_ATTACH       = 10   # trace some running process 
 33  PT_DETACH       = 11   # stop tracing a process 
 34  PT_SIGEXC       = 12   # signals as exceptions for current_proc 
 35  PT_THUPDATE     = 13   # signal for thread# 
 36  PT_ATTACHEXC    = 14   # attach to running process with signal exception 
 37  PT_FORCEQUOTA   = 30   # Enforce quota for root 
 38  PT_DENY_ATTACH  = 31 
 39   
 40  # Top-level identifiers 
 41  CTL_UNSPEC  = 0        # unused 
 42  CTL_KERN    = 1        # "high kernel": proc, limits 
 43  CTL_VM      = 2        # virtual memory 
 44  CTL_VFS     = 3        # file system, mount type is next 
 45  CTL_NET     = 4        # network, see socket.h 
 46  CTL_DEBUG   = 5        # debugging parameters 
 47  CTL_HW      = 6        # generic cpu/io 
 48  CTL_MACHDEP = 7        # machine dependent 
 49  CTL_USER    = 8        # user-level 
 50  CTL_MAXID   = 9        # number of valid top-level ids 
 51   
 52  KERN_OSTYPE          = 1    # string: system version 
 53  KERN_OSRELEASE       = 2    # string: system release 
 54  KERN_OSREV           = 3    # int: system revision 
 55  KERN_VERSION         = 4    # string: compile time info 
 56  KERN_MAXVNODES       = 5    # int: max vnodes 
 57  KERN_MAXPROC         = 6    # int: max processes 
 58  KERN_MAXFILES        = 7    # int: max open files 
 59  KERN_ARGMAX          = 8    # int: max arguments to exec 
 60  KERN_SECURELVL       = 9    # int: system security level 
 61  KERN_HOSTNAME        = 10    # string: hostname 
 62  KERN_HOSTID          = 11    # int: host identifier 
 63  KERN_CLOCKRATE       = 12    # struct: struct clockrate 
 64  KERN_VNODE           = 13    # struct: vnode structures 
 65  KERN_PROC            = 14    # struct: process entries 
 66  KERN_FILE            = 15    # struct: file entries 
 67  KERN_PROF            = 16    # node: kernel profiling info 
 68  KERN_POSIX1          = 17    # int: POSIX.1 version 
 69  KERN_NGROUPS         = 18    # int: # of supplemental group ids 
 70  KERN_JOB_CONTROL     = 19    # int: is job control available 
 71  KERN_SAVED_IDS       = 20    # int: saved set-user/group-ID 
 72  KERN_BOOTTIME        = 21    # struct: time kernel was booted 
 73  KERN_NISDOMAINNAME   = 22    # string: YP domain name 
 74  KERN_DOMAINNAME      = KERN_NISDOMAINNAME 
 75  KERN_MAXPARTITIONS   = 23    # int: number of partitions/disk 
 76  KERN_KDEBUG          = 24    # int: kernel trace points 
 77  KERN_UPDATEINTERVAL  = 25    # int: update process sleep time 
 78  KERN_OSRELDATE       = 26    # int: OS release date 
 79  KERN_NTP_PLL         = 27    # node: NTP PLL control 
 80  KERN_BOOTFILE        = 28    # string: name of booted kernel 
 81  KERN_MAXFILESPERPROC = 29    # int: max open files per proc 
 82  KERN_MAXPROCPERUID   = 30    # int: max processes per uid 
 83  KERN_DUMPDEV         = 31    # dev_t: device to dump on 
 84  KERN_IPC             = 32    # node: anything related to IPC 
 85  KERN_DUMMY           = 33    # unused 
 86  KERN_PS_STRINGS      = 34    # int: address of PS_STRINGS 
 87  KERN_USRSTACK32      = 35    # int: address of USRSTACK 
 88  KERN_LOGSIGEXIT      = 36    # int: do we log sigexit procs? 
 89  KERN_SYMFILE         = 37    # string: kernel symbol filename 
 90  KERN_PROCARGS        = 38 
 91  #/* 39 was KERN_PCSAMPLES... now deprecated 
 92  KERN_NETBOOT         = 40    # int: are we netbooted? 1=yes,0=no 
 93  KERN_PANICINFO       = 41    # node: panic UI information 
 94  KERN_SYSV            = 42    # node: System V IPC information 
 95  KERN_AFFINITY        = 43    # xxx 
 96  KERN_TRANSLATE       = 44    # xxx 
 97  KERN_CLASSIC         = KERN_TRANSLATE    # XXX backwards compat 
 98  KERN_EXEC            = 45    # xxx 
 99  KERN_CLASSICHANDLER  = KERN_EXEC # XXX backwards compatibility 
100  KERN_AIOMAX          = 46    # int: max aio requests 
101  KERN_AIOPROCMAX      = 47    # int: max aio requests per process 
102  KERN_AIOTHREADS      = 48    # int: max aio worker threads 
103  KERN_PROCARGS2       = 49 
104  KERN_COREFILE        = 50    # string: corefile format string 
105  KERN_COREDUMP        = 51    # int: whether to coredump at all 
106  KERN_SUGID_COREDUMP  = 52    # int: whether to dump SUGID cores 
107  KERN_PROCDELAYTERM   = 53    # int: set/reset current proc for delayed termination during shutdown 
108  KERN_SHREG_PRIVATIZABLE = 54    # int: can shared regions be privatized ? 
109  KERN_PROC_LOW_PRI_IO = 55    # int: set/reset current proc for low priority I/O 
110  KERN_LOW_PRI_WINDOW  = 56    # int: set/reset throttle window - milliseconds 
111  KERN_LOW_PRI_DELAY   = 57    # int: set/reset throttle delay - milliseconds 
112  KERN_POSIX           = 58    # node: posix tunables 
113  KERN_USRSTACK64      = 59    # LP64 user stack query 
114  KERN_NX_PROTECTION   = 60    # int: whether no-execute protection is enabled 
115  KERN_TFP             = 61    # Task for pid settings 
116  KERN_PROCNAME        = 62    # setup process program  name(2*MAXCOMLEN) 
117  KERN_THALTSTACK      = 63    # for compat with older x86 and does nothing 
118  KERN_SPECULATIVE_READS  = 64    # int: whether speculative reads are disabled 
119  KERN_OSVERSION       = 65    # for build number i.e. 9A127 
120  KERN_SAFEBOOT        = 66    # are we booted safe? 
121  KERN_LCTX            = 67    # node: login context 
122  KERN_RAGEVNODE       = 68 
123  KERN_TTY             = 69    # node: tty settings 
124  KERN_CHECKOPENEVT    = 70      # spi: check the VOPENEVT flag on vnodes at open time 
125  KERN_MAXID           = 71    # number of valid kern ids 
126  # # KERN_RAGEVNODE types 
127  KERN_RAGE_PROC       = 1 
128  KERN_RAGE_THREAD     = 2 
129  KERN_UNRAGE_PROC     = 3 
130  KERN_UNRAGE_THREAD   = 4 
131   
132  # # KERN_OPENEVT types 
133  KERN_OPENEVT_PROC    = 1 
134  KERN_UNOPENEVT_PROC  = 2 
135   
136  # # KERN_TFP types 
137  KERN_TFP_POLICY      = 1 
138   
139  # # KERN_TFP_POLICY values . All policies allow task port for self 
140  KERN_TFP_POLICY_DENY    = 0     # Deny Mode: None allowed except privileged 
141  KERN_TFP_POLICY_DEFAULT = 2    # Default  Mode: related ones allowed and upcall authentication 
142   
143  # # KERN_KDEBUG types 
144  KERN_KDEFLAGS        = 1 
145  KERN_KDDFLAGS        = 2 
146  KERN_KDENABLE        = 3 
147  KERN_KDSETBUF        = 4 
148  KERN_KDGETBUF        = 5 
149  KERN_KDSETUP         = 6 
150  KERN_KDREMOVE        = 7 
151  KERN_KDSETREG        = 8 
152  KERN_KDGETREG        = 9 
153  KERN_KDREADTR        = 10 
154  KERN_KDPIDTR         = 11 
155  KERN_KDTHRMAP        = 12 
156  # # Don't use 13 as it is overloaded with KERN_VNODE 
157  KERN_KDPIDEX         = 14 
158  KERN_KDSETRTCDEC     = 15 
159  KERN_KDGETENTROPY    = 16 
160   
161  # # KERN_PANICINFO types 
162  KERN_PANICINFO_MAXSIZE  = 1    # quad: panic UI image size limit 
163  KERN_PANICINFO_IMAGE    = 2    # panic UI in 8-bit kraw format 
164   
165  # * KERN_PROC subtypes 
166  KERN_PROC_ALL        = 0    # everything 
167  KERN_PROC_PID        = 1    # by process id 
168  KERN_PROC_PGRP       = 2    # by process group id 
169  KERN_PROC_SESSION    = 3    # by session of pid 
170  KERN_PROC_TTY        = 4    # by controlling tty 
171  KERN_PROC_UID        = 5    # by effective uid 
172  KERN_PROC_RUID       = 6    # by real uid 
173  KERN_PROC_LCID       = 7    # by login context id 
174   
175  # Stupid backwards perms defs... 
176  VM_PROT_READ    = 1 
177  VM_PROT_WRITE   = 2 
178  VM_PROT_EXECUTE = 4 
179   
180  # Thread status types... 
181  x86_THREAD_STATE32    = 1 
182  x86_FLOAT_STATE32     = 2 
183  x86_EXCEPTION_STATE32 = 3 
184  x86_THREAD_STATE64    = 4 
185  x86_FLOAT_STATE64     = 5 
186  x86_EXCEPTION_STATE64 = 6 
187  x86_THREAD_STATE      = 7 
188  x86_FLOAT_STATE       = 8 
189  x86_EXCEPTION_STATE   = 9 
190  x86_DEBUG_STATE32     = 10 
191  x86_DEBUG_STATE64     = 11 
192  x86_DEBUG_STATE       = 12 
193  THREAD_STATE_NONE     = 13 
194   
195 -class X86_STATE_HDR(ctypes.Structure):
196 _fields_ = [ 197 ('flavor', ctypes.c_uint32), 198 ('count', ctypes.c_uint32), 199 ]
200
201 -class STRUCT_X86_THREAD_STATE32(ctypes.Structure):
202 _fields_ = [ 203 #('tsh', X86_STATE_HDR), 204 ('eax', ctypes.c_uint32), 205 ('ebx', ctypes.c_uint32), 206 ('ecx', ctypes.c_uint32), 207 ('edx', ctypes.c_uint32), 208 ('edi', ctypes.c_uint32), 209 ('esi', ctypes.c_uint32), 210 ('ebp', ctypes.c_uint32), 211 ('esp', ctypes.c_uint32), 212 ('ss', ctypes.c_uint32), 213 ('eflags', ctypes.c_uint32), 214 ('eip', ctypes.c_uint32), 215 ('cs', ctypes.c_uint32), 216 ('ds', ctypes.c_uint32), 217 ('es', ctypes.c_uint32), 218 ('fs', ctypes.c_uint32), 219 ('gs', ctypes.c_uint32), 220 ]
221
222 -class STRUCT_X86_EXCEPTION_STATE32(ctypes.Structure):
223 _fields_ = [ 224 ('trapno', ctypes.c_uint32), 225 ('err', ctypes.c_uint32), 226 ('faultvaddr', ctypes.c_uint32), 227 ]
228
229 -class STRUCT_X86_DEBUG_STATE32(ctypes.Structure):
230 _fields_ = [ ('debug%d', ctypes.c_uint32) for i in range(8) ]
231
232 -class STRUCT_X86_THREAD_STATE64(ctypes.Structure):
233 _fields_ = [ 234 #('tsh', X86_STATE_HDR), 235 ('rax', ctypes.c_uint64), 236 ('rbx', ctypes.c_uint64), 237 ('rcx', ctypes.c_uint64), 238 ('rdx', ctypes.c_uint64), 239 ('rdi', ctypes.c_uint64), 240 ('rsi', ctypes.c_uint64), 241 ('rbp', ctypes.c_uint64), 242 ('rsp', ctypes.c_uint64), 243 ('r8', ctypes.c_uint64), 244 ('r9', ctypes.c_uint64), 245 ('r10', ctypes.c_uint64), 246 ('r11', ctypes.c_uint64), 247 ('r12', ctypes.c_uint64), 248 ('r13', ctypes.c_uint64), 249 ('r14', ctypes.c_uint64), 250 ('r15', ctypes.c_uint64), 251 ('rip', ctypes.c_uint64), 252 ('rflags', ctypes.c_uint64), 253 ('cs', ctypes.c_uint64), 254 ('fs', ctypes.c_uint64), 255 ('gs', ctypes.c_uint64), 256 ]
257 258
259 -class STRUCT_X86_EXCEPTION_STATE64(ctypes.Structure):
260 _fields_ = [ 261 ('trapno', ctypes.c_uint32), 262 ('err', ctypes.c_uint32), 263 ('faultvaddr', ctypes.c_uint64), 264 ]
265
266 -class STRUCT_X86_DEBUG_STATE64(ctypes.Structure):
267 _fields_ = [ ('debug%d', ctypes.c_uint64) for i in range(8) ]
268 269 ########################################################################### 270 # 271 # mach port enumerations 272 # 273 MACH_PORT_NULL = 0 274 275 #MACH_PORT_RIGHT_* definitions are used as arguments 276 MACH_PORT_RIGHT_SEND = 0 277 MACH_PORT_RIGHT_RECEIVE = 1 278 MACH_PORT_RIGHT_SEND_ONCE = 2 279 MACH_PORT_RIGHT_PORT_SET = 3 280 MACH_PORT_RIGHT_DEAD_NAME = 4 281 MACH_PORT_RIGHT_LABELH = 5 282 MACH_PORT_RIGHT_NUMBER = 6 283
284 -def MACH_PORT_TYPE(right):
285 return 1 << (right + 16)
286 287 MACH_PORT_TYPE_SEND = MACH_PORT_TYPE(MACH_PORT_RIGHT_SEND) 288 MACH_PORT_TYPE_RECEIVE = MACH_PORT_TYPE(MACH_PORT_RIGHT_RECEIVE) 289 MACH_PORT_TYPE_SEND_ONCE = MACH_PORT_TYPE(MACH_PORT_RIGHT_SEND_ONCE) 290 MACH_PORT_TYPE_PORT_SET = MACH_PORT_TYPE(MACH_PORT_RIGHT_PORT_SET) 291 MACH_PORT_TYPE_DEAD_NAME = MACH_PORT_TYPE(MACH_PORT_RIGHT_DEAD_NAME) 292 MACH_PORT_TYPE_LABELH = MACH_PORT_TYPE(MACH_PORT_RIGHT_LABELH) 293 294 ########################################################################### 295 # 296 # mach message types and structures 297 # 298 MACH_MSG_TIMEOUT_NONE = 0 299 MACH_MSG_OPTION_NONE = 0 300 301 MACH_SEND_MSG = 0x00000001 302 MACH_RCV_MSG = 0x00000002 303 MACH_RCV_LARGE = 0x00000004 304 305 MACH_SEND_TIMEOUT = 0x00000010 306 MACH_SEND_INTERRUPT = 0x00000040 # libmach implements 307 MACH_SEND_CANCEL = 0x00000080 308 MACH_SEND_ALWAYS = 0x00010000 # internal use only 309 MACH_SEND_TRAILER = 0x00020000 310 311 MACH_RCV_TIMEOUT = 0x00000100 312 MACH_RCV_NOTIFY = 0x00000200 313 MACH_RCV_INTERRUPT = 0x00000400 # libmach implements 314 MACH_RCV_OVERWRITE = 0x00001000 315 316 # Return codes from mach_msg... 317 MACH_RCV_TIMED_OUT = 0x10004003 318 319 MACH_MSG_TYPE_MOVE_RECEIVE = 16 # Must hold receive rights 320 MACH_MSG_TYPE_MOVE_SEND = 17 # Must hold send rights 321 MACH_MSG_TYPE_MOVE_SEND_ONCE = 18 # Must hold sendonce rights 322 MACH_MSG_TYPE_COPY_SEND = 19 # Must hold send rights 323 MACH_MSG_TYPE_MAKE_SEND = 20 # Must hold receive rights 324 MACH_MSG_TYPE_MAKE_SEND_ONCE = 21 # Must hold receive rights 325 MACH_MSG_TYPE_COPY_RECEIVE = 22 # Must hold receive rights 326 327 size_t = ctypes.c_ulong 328 329 mach_port_t = ctypes.c_uint32 330 mach_port_name_t = ctypes.c_uint32 331 mach_port_right_t = ctypes.c_uint32 332 mach_msg_size_t = ctypes.c_uint32 333 mach_msg_bits_t = ctypes.c_uint32 334 mach_msg_id_t = ctypes.c_uint32 335 336 ipc_space_t = ctypes.c_uint32 337 338 kern_return_t = ctypes.c_uint32 339
340 -class mach_msg_header_t(ctypes.Structure):
341 _fields_ = [ 342 ('msgh_bits', mach_msg_bits_t), 343 ('msgh_size', mach_msg_size_t), 344 ('msgh_remote_port', mach_port_t), 345 ('msgh_local_port', mach_port_t), 346 ('msgh_reserved', mach_msg_size_t), 347 ('msgh_id', mach_msg_id_t), 348 ]
349
350 -class mach_msg_body_t(ctypes.Structure):
351 _fields_ = [ 352 ('msgh_descriptor_count', ctypes.c_uint32), 353 ]
354
355 -class mach_msg_port_descriptor_t(ctypes.Structure):
356 _fields_ = [ 357 ('name', mach_port_t), 358 ('pad1', mach_msg_size_t), 359 ('pad2', ctypes.c_uint32), 360 ]
361
362 -class NDR_record_t(ctypes.Structure):
363 _fields_ = [ 364 ('mig_vers', ctypes.c_uint8), 365 ('if_vers', ctypes.c_uint8), 366 ('reserved', ctypes.c_uint8), 367 ('mig_encoding', ctypes.c_uint8), 368 ('int_rep', ctypes.c_uint8), 369 ('char_rep', ctypes.c_uint8), 370 ('float_rep', ctypes.c_uint8), 371 ('reserved2', ctypes.c_uint8), 372 ]
373 374 exception_type_t = ctypes.c_uint32 375 mach_msg_type_number_t = ctypes.c_uint32 376 exception_data_t = ctypes.POINTER(ctypes.c_uint32) 377 378 # the message type we receive from the kernel for exceptions
379 -class exc_msg(ctypes.Structure):
380 _fields_ = [ 381 ('Head', mach_msg_header_t), 382 #('data', ctypes.c_uint8 * 1024), 383 384 ('body', mach_msg_body_t), 385 ('thread', mach_msg_port_descriptor_t), 386 ('task', mach_msg_port_descriptor_t), 387 ('NDR', NDR_record_t), 388 ('exception', exception_type_t), 389 ('codeCnt', mach_msg_type_number_t), 390 ('codes', ctypes.c_uint32 * 128), 391 392 393 ##('codes', exception_data_t), 394 ##('pad', ctypes.c_uint8 * 512) 395 396 ]
397 398 # The response message we send back
399 -class exc_rep_msg(ctypes.Structure):
400 _fields_ = [ 401 ('Head', mach_msg_header_t), 402 ('data', ctypes.c_uint8 * 1024), 403 #('NDR', NDR_record_t), 404 #('RetCode', ctypes.c_uint32) 405 ]
406 407 ########################################################################## 408 # mach generic exception codes 409 # 410 EXC_BAD_ACCESS = 1 411 EXC_BAD_INSTRUCTION = 2 412 EXC_ARITHMETIC = 3 413 EXC_EMULATION = 4 414 EXC_SOFTWARE = 5 415 EXC_BREAKPOINT = 6 416 EXC_SYSCALL = 7 417 EXC_MACH_SYSCALL = 8 418 EXC_RPC_ALERT = 9 419 EXC_CRASH = 10 420 421 # EXC_SOFTWARE will have code[0] == EXC_SOFT_SIGNAL for posix sigs 422 EXC_SOFT_SIGNAL = 0x10003 # Unix signal exceptions 423 424 EXC_MASK_MACHINE = 0 425 EXC_MASK_BAD_ACCESS = 1 << EXC_BAD_ACCESS 426 EXC_MASK_BAD_INSTRUCTION = 1 << EXC_BAD_INSTRUCTION 427 EXC_MASK_ARITHMETIC = 1 << EXC_ARITHMETIC 428 EXC_MASK_EMULATION = 1 << EXC_EMULATION 429 EXC_MASK_SOFTWARE = 1 << EXC_SOFTWARE 430 EXC_MASK_BREAKPOINT = 1 << EXC_BREAKPOINT 431 EXC_MASK_SYSCALL = 1 << EXC_SYSCALL 432 EXC_MASK_MACH_SYSCALL = 1 << EXC_MACH_SYSCALL 433 EXC_MASK_RPC_ALERT = 1 << EXC_RPC_ALERT 434 EXC_MASK_CRASH = 1 << EXC_CRASH 435 436 EXC_MASK_ALL = (EXC_MASK_BAD_ACCESS | 437 EXC_MASK_BAD_INSTRUCTION | 438 EXC_MASK_ARITHMETIC | 439 EXC_MASK_EMULATION | 440 EXC_MASK_SOFTWARE | 441 EXC_MASK_BREAKPOINT | 442 EXC_MASK_SYSCALL | 443 EXC_MASK_MACH_SYSCALL | 444 EXC_MASK_RPC_ALERT | 445 EXC_MASK_CRASH | 446 EXC_MASK_MACHINE) 447 448 EXCEPTION_DEFAULT = 1 # Send a catch_exception_raise message including the identity. 449 EXCEPTION_STATE = 2 # Send a catch_exception_raise_state message including the thread state. 450 EXCEPTION_STATE_IDENTITY = 3 # Send a catch_exception_raise_state_identity message including the thread identity and state. 451 MACH_EXCEPTION_CODES = 0x80000000 # Send 64-bit code and subcode in the exception header 452 453 boolean_t = ctypes.c_uint32 454 pid_t = ctypes.c_uint32 455 #u_int = ctypes.c_uint32 456 #pvoid = ctypes.c_void_p 457 #fixpt_t = ctypes.c_uint32 458 #u_quad_t = ctypes.c_ulonglong 459 #sigset_t = ctypes.c_uint32 460 thread_t = ctypes.c_uint32 461 462 463 #################################################################### 464 # 465 # mach VM related stuff.... 466 # 467 vm_prot_t = ctypes.c_uint32 468 vm_inherit_t = ctypes.c_uint32 469 vm_behavior_t = ctypes.c_uint32 470 memory_object_offset_t = ctypes.c_ulonglong 471 472 VM_REGION_BASIC_INFO_64 = 9 473
474 -class vm_region_basic_info_64(ctypes.Structure):
475 _fields_ = [ 476 ('protection', vm_prot_t), 477 ('max_protection', vm_prot_t), 478 ('inheritance', vm_inherit_t), 479 ('shared', boolean_t), 480 ('reserved', boolean_t), 481 ('offset', memory_object_offset_t), 482 ('behavior', vm_behavior_t), 483 ('user_wired_count',ctypes.c_ushort), 484 ]
485 486 print 'vm_region_basic_info_64',ctypes.sizeof(vm_region_basic_info_64) 487 VM_REGION_BASIC_INFO_COUNT_64 = ctypes.sizeof(vm_region_basic_info_64) / 4 488 489 #mach_helper = ctypes.CDLL('./darwin_mach.dylib') 490 491 # 492 # These are used by the machhelper library code 493 #
494 -class DarwinDebugCtx(ctypes.Structure):
495 _fields_ = [ 496 ('dbgtask', mach_port_t), 497 ('task', mach_port_t), 498 ('portset', mach_port_name_t), 499 ('excport', mach_port_name_t), 500 ('msgin', ctypes.c_void_p), 501 ('msgout', ctypes.c_void_p), 502 ]
503
504 -class ProcessListEntry(ctypes.Structure):
505 _fields_ = [ 506 ('pid', ctypes.c_uint), 507 ('name', ctypes.c_char * 17), 508 ]
509 510 darwindir = os.path.dirname(__file__) 511 machhelp_path = os.path.join(darwindir, 'machhelper.dylib') 512 machhelper = ctypes.CDLL(machhelp_path) 513 514 #machhelper.initDebugContext.restype = ctypes.c_uint32 515 #machhelper.initDebugContext.argtypes = (ctypes.POINTER(DarwinDebugCtx), ctypes.c_uint32) 516 517 machhelper.platformPs.restype = ctypes.POINTER(ProcessListEntry) 518 519 #################################################################### 520
521 -class DarwinMixin(v_posix.PosixMixin, v_posix.PtraceMixin):
522
523 - def __init__(self):
524 v_posix.PosixMixin.__init__(self) 525 v_posix.PtraceMixin.__init__(self) 526 527 self.libc = ctypes.CDLL(c_util.find_library('c')) 528 self.myport = self.libc.mach_task_self() 529 530 self.libc.mach_port_allocate.argtypes = [ipc_space_t, mach_port_right_t, ctypes.POINTER(mach_port_name_t)] 531 self.libc.mach_port_allocate.restype = kern_return_t 532 533 self.libc.mach_vm_read.argtypes = [ mach_port_t, size_t, size_t, ctypes.POINTER(ctypes.c_void_p), ctypes.POINTER(ctypes.c_uint32)] 534 self.libc.mach_vm_read.restype = kern_return_t 535 #FIXME mach_port_insert_right 536 537 self.portset = self.newMachPort(MACH_PORT_RIGHT_PORT_SET) 538 self.excport = self.newMachRWPort() 539 self.addPortToSet(self.excport)
540
541 - def platformPs(self):
542 543 ret = [] 544 y = machhelper.platformPs() 545 i = 0 546 while y[i].pid != 0xffffffff: 547 ret.append((y[i].pid, y[i].name)) 548 i += 1 549 550 # FIXME free! 551 ret.reverse() 552 return ret
553
554 - def platformParseBinary(self, filename, baseaddr, normname):
555 pass
556
557 - def platformGetFds(self):
558 print "FIXME platformGetFds() no workie on darwin yet..." 559 return []
560
561 - def platformExec(self, cmdline):
562 pid = v_posix.PtraceMixin.platformExec(self, cmdline) 563 self.task = self.taskForPid(pid) 564 self.setExceptionPort() 565 return pid
566
567 - def _getThreadPorts(self):
568 count = ctypes.c_uint32() 569 tlist = ctypes.POINTER(thread_t)() 570 r = self.libc.task_threads(self.task, addrof(tlist), addrof(count)) 571 if r != 0: 572 raise Exception('task_threads Failed: 0x%.8x' % r) 573 574 ret = [ tlist[i] for i in range(count.value)] 575 self.libc.vm_deallocate(self.task, tlist) 576 return ret
577
578 - def platformSuspendThread(self, tid):
579 self.libc.thread_suspend(tid)
580
581 - def platformResumeThread(self, tid):
582 self.libc.thread_resume(tid)
583
584 - def platformGetThreads(self):
585 ret = {} 586 for tid in self._getThreadPorts(): 587 ret[tid] = tid 588 return ret
589
590 - def platformGetMaps(self):
591 592 maps = [] 593 address = ctypes.c_ulong(0) 594 mapsize = ctypes.c_ulong(0) 595 name = ctypes.c_uint32(0) 596 count = ctypes.c_uint32(VM_REGION_BASIC_INFO_COUNT_64) 597 info = vm_region_basic_info_64() 598 599 while True: 600 601 r = self.libc.mach_vm_region(self.task, addrof(address), 602 addrof(mapsize), VM_REGION_BASIC_INFO_64, 603 addrof(info), addrof(count), 604 addrof(name)) 605 606 # If we get told "invalid address", we have crossed into kernel land... 607 if r == 1: 608 break 609 610 if r != 0: 611 self.libc.mach_error("mach_vm_region", r) 612 raise Exception('vm_region Failed for 0x%.8x: 0x%.8x' % (address.value,r)) 613 614 perms = 0 615 p = info.protection 616 if p & VM_PROT_READ: 617 perms |= e_mem.MM_READ 618 if p & VM_PROT_WRITE: 619 perms |= e_mem.MM_WRITE 620 if p & VM_PROT_EXECUTE: 621 perms |= e_mem.MM_EXEC 622 if info.shared: 623 perms |= e_mem.MM_SHARED 624 # If we got any perms, report the map 625 if perms: 626 maps.append((address.value, mapsize.value, perms, '')) 627 628 address.value += mapsize.value 629 630 return maps
631
632 - def platformProcessEvent(self, event):
633 """ 634 Handle a mach exception message 635 """ 636 threadid, excode, codes = event 637 638 # Set the thread that signaled. 639 self.setMeta('ThreadId', threadid) 640 self.setMeta('StoppedThreadId', threadid) 641 642 self.setMeta('MachException', event) 643 644 if excode == EXC_SOFTWARE: 645 print 'exc_software' 646 647 if len(codes) != 2: 648 raise Exception('EXC_SOFTWARE with codeCnt != 2: %d' % len(codes)) 649 650 if codes[0] != EXC_SOFT_SIGNAL: 651 raise Exception('codes[0] != EXC_SOFT_SIGNAL: %.8x' % codes[0]) 652 653 sig = codes[1] 654 print 'SOFT SIG',sig 655 656 if sig == signal.SIGTRAP: 657 # FIXME I think we can catch these! 658 # Traps on posix systems are a little complicated 659 if self.stepping: 660 self.stepping = False 661 self.fireNotifiers(vtrace.NOTIFY_STEP) 662 663 # FIXME and these too... 664 elif self.checkBreakpoints(): 665 # It was either a known BP or a sendBreak() 666 return 667 668 elif self.execing: 669 self.execing = False 670 self.handleAttach() 671 672 else: 673 self._fireSignal(sig) 674 675 elif sig == signal.SIGSTOP: 676 # We get a regular POSIX stop signal on attach 677 self.handleAttach() 678 679 else: 680 self._fireSignal(sig) 681 682 elif excode == EXC_BAD_ACCESS: 683 print 'exc_bad_access',repr([hex(x) for x in codes ]) 684 self._fireSignal(0) 685 686 elif excode == EXC_CRASH: 687 print 'exc_crash' 688 print 'Crash:',repr([hex(x) for x in codes]) 689 self._fireExit(0xffffffff) 690 691 elif excode == EXC_BREAKPOINT: 692 print 'exc_breakpoint',codes 693 self._fireSignal(0) # FIXME 694 695 else: 696 print 'Unprocessed Exception Type: %d' % excode 697 self.fireNotifiers(vtrace.NOTIFY_SIGNAL) 698 699 return
700
701 - def platformAttach(self, pid):
702 print 'CLASSIC',machhelper.is_pid_classic(pid) 703 self.task = self.taskForPid(pid) 704 self.setExceptionPort() 705 if v_posix.ptrace(PT_ATTACHEXC, pid, 0, 0) != 0: 706 #self.libc.perror('ptrace( PT_ATTACHEXC, %d, 0, 0) Failed' % (pid)) 707 raise Exception("PT_ATTACH failed!")
708 #FIXME setMeta("ExeName", stuff) 709 #self.setMeta("ExeName", self._findExe(pid)) 710
711 - def taskForPid(self, pid):
712 task = ctypes.c_uint32() 713 ret = self.libc.task_for_pid(self.myport, pid, addrof(task)) 714 if ret != 0: 715 raise Exception('task_for_pid failed: 0x%.8x\n' % ret) 716 return task.value
717
718 - def newMachPort(self, right):
719 port = mach_port_name_t() 720 ret = self.libc.mach_port_allocate(self.myport, right, addrof(port)) 721 if ret != 0: 722 raise Exception('mach_port_allocate (right: %d) failed: 0x%.8x' % (right, ret)) 723 return port.value
724
725 - def newMachRWPort(self):
726 port = self.newMachPort(MACH_PORT_RIGHT_RECEIVE) 727 r = self.libc.mach_port_insert_right(self.myport, port, port, MACH_MSG_TYPE_MAKE_SEND) 728 if r != 0: 729 raise Exception('mach_port_insert_right (MACH_PORT_RIGHT_RECEIVE) Failed: 0x%.8x' % r) 730 return port
731
732 - def addPortToSet(self, port):
733 r = self.libc.mach_port_move_member(self.myport, port, self.portset) 734 if r != 0: 735 raise Exception('mach_port_move_member for portset failed: 0x%.8x' % r)
736
737 - def setExceptionPort(self):
738 # Set the target task's exception port to our excport 739 #r = self.libc.task_set_exception_ports(self.task, EXC_MASK_ALL, self.excport, 740 r = self.libc.task_set_exception_ports(self.task, EXC_MASK_SOFTWARE, self.excport, 741 EXCEPTION_DEFAULT, THREAD_STATE_NONE) 742 if r != 0: 743 raise Exception('task_set_exception_ports failed: 0x%.8x' % r)
744
745 - def _getNextExc(self, timeout=MACH_MSG_TIMEOUT_NONE):
746 exc = exc_msg() 747 r = self.libc.mach_msg(addrof(exc), 748 #MACH_RCV_MSG|MACH_RCV_LARGE|MACH_RCV_TIMEOUT, 749 MACH_RCV_MSG|MACH_RCV_INTERRUPT, 750 0, # Send size... 751 ctypes.sizeof(exc), # Recv msg size 752 self.excport, 753 timeout, 754 MACH_PORT_NULL) 755 if r == MACH_RCV_TIMED_OUT: 756 return None 757 if r != 0: 758 raise Exception('mach_msg (RECV) failed: 0x%.8x' % r) 759 760 #print 'BITS',hex(exc.Head.msgh_bits) 761 #print 'ID',exc.Head.msgh_id 762 #print 'EXCEPTION',exc.exception 763 #print 'codeCnt', exc.codeCnt 764 #for i in range(exc.codeCnt): 765 #print 'code: 0x%.16x' % exc.codes[i] 766 767 return exc
768
769 - def platformWait(self):
770 # Wait for a mach message on the exception port 771 exc = None 772 while exc == None: 773 exc = self._getNextExc() 774 print 'EXC',exc 775 776 print 'EXC THREAD',exc.thread.name 777 778 self.setMeta('ThreadId', exc.thread.name) 779 self.setMeta('StoppedThreadId', exc.thread.name) 780 #e2 = self._getNextExc(timeout=0) 781 #if e2 != None: 782 #print "ALSO GOT",e2 783 784 # Suspend the task so reading etc is safe... 785 self.libc.task_suspend(self.task) 786 787 # Sometimes there are still posix signals anyway... 788 while os.waitpid(-1, os.WNOHANG) != (0,0): 789 pass 790 791 # NOTE We must extract *all* needed info from the event here! 792 codes = [exc.codes[i] for i in range(exc.codeCnt)] 793 ret = (exc.thread.name, exc.exception, codes) 794 795 res = self.buildExcResp(exc) 796 797 x = self.libc.mach_msg(addrof(res), MACH_SEND_MSG, ctypes.sizeof(res),0,MACH_MSG_TIMEOUT_NONE,MACH_PORT_NULL) 798 if x != 0: 799 raise Exception('mach_msg MACH_SEND_MSG failed: 0x%.8x' % (x,)) 800 801 return ret
802 #return exc 803
804 - def buildExcResp(self, exc):
805 # This is from straight reversing exc_server from libc... 806 807 #res = exc_rep_msg() 808 809 #res.Head.msgh_bits = exc.Head.msgh_bits & 0xff 810 #res.Head.msgh_size = 0x24 811 #res.Head.msgh_remote_port = exc.Head.msgh_remote_port 812 #res.Head.msgh_local_port = 0 813 #res.Head.msgh_id = exc.Head.msgh_id + 0x64 814 #res.NDR.int_rep = 1 815 #res.RetCode = 0 816 817 #print 'exc_server',self.libc.exc_server(ctypes.pointer(exc), ctypes.pointer(res)) 818 #return res 819 820 print 'exc_server',self.libc.exc_server(ctypes.pointer(exc), ctypes.pointer(exc)) 821 return exc
822
823 - def platformStepi(self):
824 self.stepping = True 825 tid = self.getMeta("ThreadId", 0) 826 if v_posix.ptrace(v_posix.PT_STEP, self.pid, 1, 0) != 0: 827 raise Exception("ERROR ptrace failed!") 828 self.libc.task_resume(self.task)
829
830 - def platformContinue(self):
831 sig = self.getCurrentSignal() 832 if sig == None: 833 sig = 0 834 print 'PT_THUPDATE',v_posix.ptrace(PT_THUPDATE, self.pid, self.getMeta('StoppedThreadId'), sig) 835 v_posix.ptrace(PT_CONTINUE, self.pid, 1, sig) 836 self.libc.task_resume(self.task)
837
838 - def platformDetach(self):
839 #for tid in self.getThreads().keys(): 840 #self.libc.thread_resume(tid) 841 self.libc.task_resume(self.task) 842 v_posix.ptrace(PT_DETACH, self.pid, 0, 0)
843
844 - def platformReadMemory(self, address, size):
845 pval = ctypes.c_void_p(0) 846 sval = ctypes.c_uint32(0) 847 r = self.libc.mach_vm_read(self.task, address, size, addrof(pval), addrof(sval)); 848 #r = self.libc.vm_read(self.task, address, size, addrof(pval), addrof(sval)); 849 if r != 0: 850 raise Exception('mach_vm_read failed at 0x%.8x: 0x%.8x' % (address,r)) 851 buf = ctypes.string_at(pval.value, sval.value) 852 self.libc.vm_deallocate(self.myport, pval, sval) 853 return buf
854
855 - def platformWriteMemory(self, address, data):
856 r = self.libc.vm_write(self.task, address, data, len(data)) 857 if r != 0: 858 raise Exception('vm_write failed: 0x%.8x' % r)
859 860 # FIXME use vm_allocate for allocate memory 861 # FIXME use vm_protect 862
863 -class Darwini386Trace( 864 vtrace.Trace, 865 DarwinMixin, 866 v_i386.i386Mixin, 867 v_base.TracerBase):
868
869 - def __init__(self):
870 vtrace.Trace.__init__(self) 871 v_base.TracerBase.__init__(self) 872 v_i386.i386Mixin.__init__(self) 873 DarwinMixin.__init__(self)
874
875 - def getThreadException(self, tid):
876 # Each arch trace must implement this... 877 state = STRUCT_X86_EXCEPTION_STATE32() 878 scount = ctypes.c_uint32(ctypes.sizeof(state) / 4) 879 ret = self.libc.thread_get_state(tid, x86_EXCEPTION_STATE32, addrof(state), addrof(scount)); 880 if ret != 0: 881 raise Exception('thread_get_state failed: 0x%.8x' % ret) 882 return state.trapno, state.err, state.faultvaddr
883
884 - def platformGetRegCtx(self, tid):
885 ctx = self.archGetRegCtx() 886 # NOTE: the tid *is* the port... 887 888 state = STRUCT_X86_THREAD_STATE32() 889 scount = ctypes.c_uint32(ctypes.sizeof(state) / 4) 890 ret = self.libc.thread_get_state(tid, x86_THREAD_STATE32, addrof(state), addrof(scount)); 891 if ret != 0: 892 raise Exception('thread_get_state (THREAD_STATE32) failed: 0x%.8x' % ret) 893 ctx._rctx_Import(state) 894 895 state = STRUCT_X86_DEBUG_STATE32() 896 scount = ctypes.c_uint32(ctypes.sizeof(state) / 4) 897 ret = self.libc.thread_get_state(tid, x86_DEBUG_STATE32, addrof(state), addrof(scount)); 898 if ret != 0: 899 raise Exception('thread_get_state (DEBUG_STATE32) failed: 0x%.8x' % ret) 900 ctx._rctx_Import(state) 901 902 return ctx
903
904 - def platformSetRegCtx(self, tid, ctx):
905 906 state = STRUCT_X86_THREAD_STATE32() 907 908 # Sync up a struct first... 909 scount = ctypes.c_uint32(ctypes.sizeof(state) / 4) 910 ret = self.libc.thread_get_state(tid, x86_THREAD_STATE32, addrof(state), addrof(scount)); 911 if ret != 0: 912 raise Exception('thread_get_state (THREAD_STATE32) failed: 0x%.8x' % ret) 913 914 # Export our shit into it... 915 ctx._rctx_Export(state) 916 917 scount = ctypes.sizeof(state) / 4 918 r = self.libc.thread_set_state(tid, x86_THREAD_STATE32, addrof(state), scount) 919 if r != 0: 920 raise Exception('thread_set_state (THREAD_STATE32) failed: 0x%.8x' % r) 921 922 state = STRUCT_X86_DEBUG_STATE32() 923 ctx._rctx_Export(state) 924 scount = ctypes.sizeof(state) / 4 925 r = self.libc.thread_set_state(tid, x86_DEBUG_STATE32, addrof(state), scount) 926 if r != 0: 927 raise Exception('thread_set_state (DEBUG_STATE32) failed: 0x%.8x' % r)
928
929 -class DarwinAmd64Trace( 930 vtrace.Trace, 931 DarwinMixin, 932 v_amd64.Amd64Mixin, 933 v_base.TracerBase):
934
935 - def __init__(self):
936 vtrace.Trace.__init__(self) 937 v_base.TracerBase.__init__(self) 938 v_amd64.Amd64Mixin.__init__(self) 939 DarwinMixin.__init__(self)
940
941 - def getThreadException(self, tid):
942 # Each arch trace must implement this... 943 state = STRUCT_X86_EXCEPTION_STATE64() 944 scount = ctypes.c_uint32(ctypes.sizeof(state) / 8) 945 ret = self.libc.thread_get_state(tid, x86_EXCEPTION_STATE64, addrof(state), addrof(scount)); 946 if ret != 0: 947 raise Exception('thread_get_state failed: 0x%.8x' % ret) 948 return state.trapno, state.err, state.faultvaddr
949
950 - def platformGetRegCtx(self, tid):
951 ctx = self.archGetRegCtx() 952 # NOTE: the tid *is* the port... 953 954 state = STRUCT_X86_THREAD_STATE64() 955 scount = ctypes.c_uint32(ctypes.sizeof(state) / 4) 956 ret = self.libc.thread_get_state(tid, x86_THREAD_STATE64, addrof(state), addrof(scount)); 957 if ret != 0: 958 self.libc.mach_error("thread_get_state x86_THREAD_STATE64 failed:", ret) 959 raise Exception('thread_get_state (THREAD_STATE64) failed: 0x%.8x' % ret) 960 ctx._rctx_Import(state) 961 962 state = STRUCT_X86_DEBUG_STATE64() 963 scount = ctypes.c_uint32(ctypes.sizeof(state) / 4) 964 ret = self.libc.thread_get_state(tid, x86_DEBUG_STATE64, addrof(state), addrof(scount)); 965 if ret != 0: 966 self.libc.mach_error("thread_get_state x86_DEBUG_STATE64 failed:", ret) 967 raise Exception('thread_get_state (DEBUG_STATE64) failed: 0x%.8x' % ret) 968 ctx._rctx_Import(state) 969 970 return ctx
971
972 - def platformSetRegCtx(self, tid, ctx):
973 974 state = STRUCT_X86_THREAD_STATE64() 975 976 # Sync up a struct first... 977 scount = ctypes.c_uint32(ctypes.sizeof(state) / 8) 978 ret = self.libc.thread_get_state(tid, x86_THREAD_STATE64, addrof(state), addrof(scount)); 979 if ret != 0: 980 raise Exception('thread_get_state (THREAD_STATE64) failed: 0x%.8x' % ret) 981 982 # Export our shit into it... 983 ctx._rctx_Export(state) 984 985 scount = ctypes.sizeof(state) / 8 986 r = self.libc.thread_set_state(tid, x86_THREAD_STATE64, addrof(state), scount) 987 if r != 0: 988 raise Exception('thread_set_state (THREAD_STATE64) failed: 0x%.8x' % r) 989 990 state = STRUCT_X86_DEBUG_STATE64() 991 ctx._rctx_Export(state) 992 scount = ctypes.sizeof(state) / 8 993 r = self.libc.thread_set_state(tid, x86_DEBUG_STATE64, addrof(state), scount) 994 if r != 0: 995 raise Exception('thread_set_state (DEBUG_STATE64) failed: 0x%.8x' % r)
996