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 512 #################################################################### 513
514 -class DarwinMixin(v_posix.PosixMixin, v_posix.PtraceMixin):
515
516 - def __init__(self):
517 v_posix.PosixMixin.__init__(self) 518 v_posix.PtraceMixin.__init__(self) 519 520 self.libc = ctypes.CDLL(c_util.find_library('c')) 521 self.myport = self.libc.mach_task_self() 522 523 self.libc.mach_port_allocate.argtypes = [ipc_space_t, mach_port_right_t, ctypes.POINTER(mach_port_name_t)] 524 self.libc.mach_port_allocate.restype = kern_return_t 525 526 self.libc.mach_vm_read.argtypes = [ mach_port_t, size_t, size_t, ctypes.POINTER(ctypes.c_void_p), ctypes.POINTER(ctypes.c_uint32)] 527 self.libc.mach_vm_read.restype = kern_return_t 528 529 self.libc.ptrace.restype = ctypes.c_int 530 self.libc.ptrace.argtypes = [ctypes.c_int, ctypes.c_uint32, ctypes.c_size_t, ctypes.c_int] 531 532 machhelp_path = os.path.join(darwindir, 'machhelper.dylib') 533 self.machhelper = ctypes.CDLL(machhelp_path) 534 self.machhelper.platformPs.restype = ctypes.POINTER(ProcessListEntry) 535 536 self.useptrace = False 537 538 self.portset = self.newMachPort(MACH_PORT_RIGHT_PORT_SET) 539 self.excport = self.newMachRWPort() 540 self.addPortToSet(self.excport)
541
542 - def platformPs(self):
543 544 ret = [] 545 y = self.machhelper.platformPs() 546 i = 0 547 while y[i].pid != 0xffffffff: 548 ret.append((y[i].pid, y[i].name)) 549 i += 1 550 551 # FIXME free! 552 ret.reverse() 553 return ret
554
555 - def platformParseBinary(self, filename, baseaddr, normname):
556 pass
557
558 - def platformGetFds(self):
559 print "FIXME platformGetFds() no workie on darwin yet..." 560 return []
561
562 - def platformExec(self, cmdline):
563 pid = v_posix.PtraceMixin.platformExec(self, cmdline) 564 self.task = self.taskForPid(pid) 565 self.setExceptionPort() 566 return pid
567
568 - def _getThreadPorts(self):
569 count = ctypes.c_uint32() 570 tlist = ctypes.POINTER(thread_t)() 571 assert( self.libc.task_threads(self.task, addrof(tlist), addrof(count)) == 0 ) 572 ret = [ tlist[i] for i in range(count.value)] 573 self.libc.vm_deallocate(self.task, tlist) 574 return ret
575
576 - def platformSuspendThread(self, tid):
577 self.libc.thread_suspend(tid)
578
579 - def platformResumeThread(self, tid):
580 self.libc.thread_resume(tid)
581
582 - def platformGetThreads(self):
583 ret = {} 584 for tid in self._getThreadPorts(): 585 ret[tid] = tid 586 return ret
587
588 - def platformGetMaps(self):
589 maps = [] 590 address = ctypes.c_ulong(0) 591 mapsize = ctypes.c_ulong(0) 592 name = ctypes.c_uint32(0) 593 count = ctypes.c_uint32(VM_REGION_BASIC_INFO_COUNT_64) 594 info = vm_region_basic_info_64() 595 596 while True: 597 598 r = self.libc.mach_vm_region(self.task, addrof(address), 599 addrof(mapsize), VM_REGION_BASIC_INFO_64, 600 addrof(info), addrof(count), 601 addrof(name)) 602 603 # If we get told "invalid address", we have crossed into kernel land... 604 if r == 1: 605 break 606 607 if r != 0: 608 self.libc.mach_error("mach_vm_region", r) 609 raise Exception('vm_region Failed for 0x%.8x: 0x%.8x' % (address.value,r)) 610 611 perms = 0 612 p = info.protection 613 if p & VM_PROT_READ: 614 perms |= e_mem.MM_READ 615 if p & VM_PROT_WRITE: 616 perms |= e_mem.MM_WRITE 617 if p & VM_PROT_EXECUTE: 618 perms |= e_mem.MM_EXEC 619 if info.shared: 620 perms |= e_mem.MM_SHARED 621 # If we got any perms, report the map 622 if perms: 623 maps.append((address.value, mapsize.value, perms, '')) 624 625 address.value += mapsize.value 626 627 return maps
628
629 - def handlePosixSignal(self, sig):
630 631 if sig == signal.SIGTRAP: 632 # FIXME I think we can catch these! 633 # Traps on posix systems are a little complicated 634 if self.stepping: 635 self.stepping = False 636 self.fireNotifiers(vtrace.NOTIFY_STEP) 637 638 # FIXME and these too... 639 elif self.checkBreakpoints(): 640 # It was either a known BP or a sendBreak() 641 return 642 643 elif self.execing: 644 self.execing = False 645 self.handleAttach() 646 647 else: 648 self._fireSignal(sig) 649 650 elif sig == signal.SIGSTOP: 651 # We get a regular POSIX stop signal on attach 652 #self.attaching = False 653 self.handleAttach() 654 655 else: 656 self._fireSignal(sig)
657
658 - def platformProcessEvent(self, event):
659 """ 660 Handle a mach exception message 661 """ 662 #if self.attaching: 663 #self.useptrace = True 664 #return self.handlePosixSignal(event) 665 666 #self.useptrace = False 667 668 # Some event states that need to be reset 669 self.softexc = False 670 671 threadid, excode, codes = event 672 673 # Set the thread that signaled. 674 self.setMeta('ThreadId', threadid) 675 self.setMeta('StoppedThreadId', threadid) 676 677 self.setMeta('MachException', event) 678 679 if excode == EXC_SOFTWARE: 680 681 self.softexc = True 682 683 assert( len(codes) == 2 ) 684 assert( codes[0] == EXC_SOFT_SIGNAL ) 685 686 sig = codes[1] 687 self.handlePosixSignal(sig) 688 689 elif excode == EXC_BAD_ACCESS: 690 print 'exc_bad_access',repr([hex(x) for x in codes ]) 691 signo = signal.SIGSEGV 692 #if codes[0] == KERN_INVALID_ADDRESS: 693 #signo = signal.SIGBUS 694 695 self._fireSignal(signo) 696 697 elif excode == EXC_BAD_INSTRUCTION: 698 print 'exc_bad_instruction',repr([hex(x) for x in codes ]) 699 self._fireSignal(signal.SIGILL) 700 701 elif excode == EXC_CRASH: 702 print 'exc_crash' 703 print 'Crash:',repr([hex(x) for x in codes]) 704 self._fireExit(0xffffffff) 705 706 elif excode == EXC_BREAKPOINT: 707 print 'exc_breakpoint',codes 708 self.handlePosixSignal(signal.SIGTRAP) 709 710 else: 711 print 'Unprocessed Exception Type: %d' % excode 712 self.fireNotifiers(vtrace.NOTIFY_SIGNAL) 713 714 return
715
716 - def platformAttach(self, pid):
717 #print 'CLASSIC',self.machhelper.is_pid_classic(pid) 718 #self.attaching = True 719 self.task = self.taskForPid(pid) 720 self.setExceptionPort() 721 assert( self.libc.ptrace(PT_ATTACHEXC, pid, 0, 0) == 0 )
722
723 - def taskForPid(self, pid):
724 task = ctypes.c_uint32() 725 ret = self.libc.task_for_pid(self.myport, pid, addrof(task)) 726 if ret != 0: 727 raise Exception('task_for_pid failed: 0x%.8x\n' % ret) 728 return task.value
729
730 - def newMachPort(self, right):
731 port = mach_port_name_t() 732 assert( self.libc.mach_port_allocate(self.myport, right, addrof(port)) == 0) 733 return port.value
734
735 - def newMachRWPort(self):
736 port = self.newMachPort(MACH_PORT_RIGHT_RECEIVE) 737 assert( self.libc.mach_port_insert_right(self.myport, port, port, MACH_MSG_TYPE_MAKE_SEND) == 0 ) 738 return port
739
740 - def addPortToSet(self, port):
741 assert( self.libc.mach_port_move_member(self.myport, port, self.portset) == 0 )
742
743 - def setExceptionPort(self):
744 # Set the target task's exception port to our excport 745 #r = self.libc.task_set_exception_ports(self.task, EXC_MASK_SOFTWARE, self.excport, 746 r = self.libc.task_set_exception_ports( self.task, 747 EXC_MASK_ALL, 748 self.excport, 749 EXCEPTION_DEFAULT, 750 THREAD_STATE_NONE) 751 if r != 0: 752 raise Exception('task_set_exception_ports failed: 0x%.8x' % r)
753
754 - def _getNextExc(self, timeout=None):
755 756 exc = exc_msg() 757 758 flags = MACH_RCV_MSG | MACH_RCV_LARGE 759 if timeout != None: 760 flags |= MACH_RCV_TIMEOUT 761 762 r = self.libc.mach_msg(addrof(exc), 763 flags, 764 0, # Send size... 765 ctypes.sizeof(exc), # Recv msg size 766 self.excport, 767 timeout, 768 MACH_PORT_NULL) 769 770 if r == MACH_RCV_TIMED_OUT: 771 return None 772 773 if r != 0: 774 raise Exception('mach_msg (RECV) failed: 0x%.8x' % r) 775 776 return exc
777
778 - def platformWait(self):
779 # Wait for a mach message on the exception port 780 781 #exc = None 782 #while exc == None: 783 #exc = self._getNextExc() 784 785 #self.setMeta('ThreadId', exc.thread.name) 786 #self.setMeta('StoppedThreadId', exc.thread.name) 787 788 #e2 = self._getNextExc(timeout=0) 789 #if e2 != None: 790 #print "ALSO GOT",e2 791 792 793 # Sometimes there are still posix signals anyway... 794 #while os.waitpid(-1, os.WNOHANG) != (0,0): 795 #pass 796 797 #if self.attaching: 798 #pid,status = os.waitpid(self.pid, 0) 799 #return os.WSTOPSIG(status) 800 801 #pid,status = os.waitpid(self.pid, 0) 802 exc = self._getNextExc() 803 804 # Suspend the task so reading etc is safe... 805 self.libc.task_suspend(self.task) 806 807 # NOTE We must extract *all* needed info from the event here! 808 codes = [exc.codes[i] for i in range(exc.codeCnt)] 809 ret = (exc.thread.name, exc.exception, codes) 810 811 self.setMeta('MachExcMsg', exc) 812 #self.sendExcResp(exc) 813 814 return ret
815
816 - def sendExcResp(self, exc, maskexc=False):
817 818 res = self.buildExcResp(exc, maskexc=maskexc) 819 x = self.libc.mach_msg( addrof(res), 820 MACH_SEND_MSG, 821 res.Head.msgh_size, 822 0, 823 res.Head.msgh_remote_port, 824 MACH_MSG_TIMEOUT_NONE, 825 MACH_PORT_NULL) 826 827 if x != 0: 828 raise Exception('mach_msg MACH_SEND_MSG failed: 0x%.8x' % (x,))
829
830 - def buildExcResp(self, exc, maskexc=False):
831 res = exc_rep_msg() 832 self.machhelper.vtrace_exc_server(ctypes.pointer(exc.Head), ctypes.pointer(res.Head), maskexc) 833 return res
834
835 - def platformStepi(self):
836 self.stepping = True 837 838 exc = self.getMeta('MachExcMsg') 839 if exc != None: 840 self.setMeta('MachExcMsg', None) 841 maskexc = ( self.getCurrentSignal() == None ) 842 self.sendExcResp(exc, maskexc=maskexc) 843 844 assert( self.libc.task_resume(self.task) == 0 ) 845 assert( self.libc.ptrace(PT_STEP, self.pid, 1, 0) == 0 )
846
847 - def platformContinue(self):
848 849 sig = self.getCurrentSignal() 850 if sig == None: 851 sig = 0 852 853 #threadid = self.getMeta('StoppedThreadId', 0) 854 #if self.softexc: 855 #assert( self.macptrace(PT_THUPDATE, self.pid, threadid, sig) == 0 ) 856 857 # If we have a mach message to respond to, lets do that.... 858 exc = self.getMeta('MachExcMsg') 859 if exc != None: 860 self.setMeta('MachExcMsg', None) 861 maskexc = ( self.getCurrentSignal() == None ) 862 self.sendExcResp(exc, maskexc=maskexc) 863 864 #if self.useptrace: 865 #assert( self.libc.ptrace(PT_THUPDATE, self.pid, threadid, sig) == 0 ) 866 #assert( self.libc.ptrace(PT_CONTINUE, self.pid, 1, sig) == 0 ) 867 #return 868 869 if self.softexc: 870 assert( self.macptrace(PT_CONTINUE, self.pid, 1, sig) == 0 ) 871 872 assert( self.libc.task_resume(self.task) == 0 )
873
874 - def macptrace(self, request, pid, addr, data, zok=True):
875 ret = self.libc.ptrace(request, pid, addr, data) 876 if ret != 0 and zok: 877 self.libc.perror('macptrace: ') 878 return ret
879
880 - def platformDetach(self):
881 assert( self.libc.task_resume(self.task) == 0 ) 882 assert( self.macptrace(PT_DETACH, self.pid, 0, 0) == 0 ) 883 884 print 'DETACH' 885 #for threadport in self._getThreadPorts(): 886 #print 'threadport', self.libc.mach_port_deallocate(self.myport, threadport) 887 888 print 'askport',self.libc.mach_port_deallocate(self.myport, self.task) 889 print 'excport',self.libc.mach_port_deallocate(self.myport, self.excport) 890 print 'portset',self.libc.mach_port_deallocate(self.myport, self.portset)
891
892 - def platformReadMemory(self, address, size):
893 pval = ctypes.c_void_p(0) 894 sval = ctypes.c_uint32(0) 895 assert( self.libc.mach_vm_read(self.task, address, size, addrof(pval), addrof(sval)) == 0 ) 896 buf = ctypes.string_at(pval.value, sval.value) 897 assert( self.libc.vm_deallocate(self.myport, pval, sval) == 0 ) 898 return buf
899
900 - def platformWriteMemory(self, address, data):
901 print 'WRITE'*100 902 assert( self.libc.vm_write(self.task, address, data, len(data)) == 0 )
903 904 # FIXME use vm_allocate for allocate memory 905 # FIXME use vm_protect 906
907 -class Darwini386Trace( 908 vtrace.Trace, 909 DarwinMixin, 910 v_i386.i386Mixin, 911 v_base.TracerBase):
912
913 - def __init__(self):
914 vtrace.Trace.__init__(self) 915 v_base.TracerBase.__init__(self) 916 v_i386.i386Mixin.__init__(self) 917 DarwinMixin.__init__(self)
918
919 - def getThreadException(self, tid):
920 # Each arch trace must implement this... 921 state = STRUCT_X86_EXCEPTION_STATE32() 922 scount = ctypes.c_uint32(ctypes.sizeof(state) / 4) 923 ret = self.libc.thread_get_state(tid, x86_EXCEPTION_STATE32, addrof(state), addrof(scount)); 924 if ret != 0: 925 raise Exception('thread_get_state failed: 0x%.8x' % ret) 926 return state.trapno, state.err, state.faultvaddr
927
928 - def platformGetRegCtx(self, tid):
929 ctx = self.archGetRegCtx() 930 # NOTE: the tid *is* the port... 931 932 state = STRUCT_X86_THREAD_STATE32() 933 scount = ctypes.c_uint32(ctypes.sizeof(state) / 4) 934 ret = self.libc.thread_get_state(tid, x86_THREAD_STATE32, addrof(state), addrof(scount)); 935 if ret != 0: 936 raise Exception('thread_get_state (THREAD_STATE32) failed: 0x%.8x' % ret) 937 ctx._rctx_Import(state) 938 939 state = STRUCT_X86_DEBUG_STATE32() 940 scount = ctypes.c_uint32(ctypes.sizeof(state) / 4) 941 ret = self.libc.thread_get_state(tid, x86_DEBUG_STATE32, addrof(state), addrof(scount)); 942 if ret != 0: 943 raise Exception('thread_get_state (DEBUG_STATE32) failed: 0x%.8x' % ret) 944 ctx._rctx_Import(state) 945 946 return ctx
947
948 - def platformSetRegCtx(self, tid, ctx):
949 state = STRUCT_X86_THREAD_STATE32() 950 951 # Sync up a struct first... 952 scount = ctypes.c_uint32(ctypes.sizeof(state) / 4) 953 ret = self.libc.thread_get_state(tid, x86_THREAD_STATE32, addrof(state), addrof(scount)); 954 if ret != 0: 955 raise Exception('thread_get_state (THREAD_STATE32) failed: 0x%.8x' % ret) 956 957 # Export our shit into it... 958 ctx._rctx_Export(state) 959 960 scount = ctypes.sizeof(state) / 4 961 r = self.libc.thread_set_state(tid, x86_THREAD_STATE32, addrof(state), scount) 962 if r != 0: 963 raise Exception('thread_set_state (THREAD_STATE32) failed: 0x%.8x' % r) 964 965 state = STRUCT_X86_DEBUG_STATE32() 966 ctx._rctx_Export(state) 967 scount = ctypes.sizeof(state) / 4 968 r = self.libc.thread_set_state(tid, x86_DEBUG_STATE32, addrof(state), scount) 969 if r != 0: 970 raise Exception('thread_set_state (DEBUG_STATE32) failed: 0x%.8x' % r)
971
972 -class DarwinAmd64Trace( 973 vtrace.Trace, 974 DarwinMixin, 975 v_amd64.Amd64Mixin, 976 v_base.TracerBase):
977
978 - def __init__(self):
979 vtrace.Trace.__init__(self) 980 v_base.TracerBase.__init__(self) 981 v_amd64.Amd64Mixin.__init__(self) 982 DarwinMixin.__init__(self)
983
984 - def getThreadException(self, tid):
985 # Each arch trace must implement this... 986 state = STRUCT_X86_EXCEPTION_STATE64() 987 scount = ctypes.c_uint32(ctypes.sizeof(state) / 8) 988 ret = self.libc.thread_get_state(tid, x86_EXCEPTION_STATE64, addrof(state), addrof(scount)); 989 if ret != 0: 990 raise Exception('thread_get_state failed: 0x%.8x' % ret) 991 return state.trapno, state.err, state.faultvaddr
992
993 - def platformGetRegCtx(self, tid):
994 ctx = self.archGetRegCtx() 995 # NOTE: the tid *is* the port... 996 997 state = STRUCT_X86_THREAD_STATE64() 998 scount = ctypes.c_uint32(ctypes.sizeof(state) / 4) 999 ret = self.libc.thread_get_state(tid, x86_THREAD_STATE64, addrof(state), addrof(scount)); 1000 if ret != 0: 1001 self.libc.mach_error("thread_get_state x86_THREAD_STATE64 failed:", ret) 1002 raise Exception('thread_get_state (THREAD_STATE64) failed: 0x%.8x' % ret) 1003 ctx._rctx_Import(state) 1004 1005 state = STRUCT_X86_DEBUG_STATE64() 1006 scount = ctypes.c_uint32(ctypes.sizeof(state) / 4) 1007 ret = self.libc.thread_get_state(tid, x86_DEBUG_STATE64, addrof(state), addrof(scount)); 1008 if ret != 0: 1009 self.libc.mach_error("thread_get_state x86_DEBUG_STATE64 failed:", ret) 1010 raise Exception('thread_get_state (DEBUG_STATE64) failed: 0x%.8x' % ret) 1011 ctx._rctx_Import(state) 1012 1013 return ctx
1014
1015 - def platformSetRegCtx(self, tid, ctx):
1016 1017 state = STRUCT_X86_THREAD_STATE64() 1018 1019 # Sync up a struct first... 1020 scount = ctypes.c_uint32(ctypes.sizeof(state) / 8) 1021 ret = self.libc.thread_get_state(tid, x86_THREAD_STATE64, addrof(state), addrof(scount)); 1022 if ret != 0: 1023 raise Exception('thread_get_state (THREAD_STATE64) failed: 0x%.8x' % ret) 1024 1025 # Export our shit into it... 1026 ctx._rctx_Export(state) 1027 1028 scount = ctypes.sizeof(state) / 8 1029 r = self.libc.thread_set_state(tid, x86_THREAD_STATE64, addrof(state), scount) 1030 if r != 0: 1031 raise Exception('thread_set_state (THREAD_STATE64) failed: 0x%.8x' % r) 1032 1033 state = STRUCT_X86_DEBUG_STATE64() 1034 ctx._rctx_Export(state) 1035 scount = ctypes.sizeof(state) / 8 1036 r = self.libc.thread_set_state(tid, x86_DEBUG_STATE64, addrof(state), scount) 1037 if r != 0: 1038 raise Exception('thread_set_state (DEBUG_STATE64) failed: 0x%.8x' % r)
1039