(lldb) watch set var global (lldb) watch modify -c ‘(global==5)’ (lldb) watch list (lldb) about to write to ‘global’…
启动或附加到您的程序
要在lldb中启动程序,我们使用“process launch”命令或其内置别名之一: (lldb) process launch (lldb) run (lldb) r
您还可以按进程ID或进程名称附加到进程。当按名称附加到进程时,lldb还支持“-waitfor”选项,该选项等待显示该名称的下一个进程,并附加到该进程 (lldb) process attach –pid 123 (lldb) process attach –name Sketch (lldb) process attach –name Sketch –waitfor
启动或附加到进程后,您的进程可能会在某处停止:
1 2 3 4 5
(lldb) process attach -p 12345 Process46915 Attaching Process46915 Stopped 1 of 3 threads stopped with reasons: * thread #1: tid = 0x2c03, 0x00007fff85cac76a, where = libSystem.B.dylib`__getdirentries64 + 10, stop reason = signal = SIGSTOP, queue = com.apple.main-thread
控制你的程序
启动后,我们可以继续,直到我们达到断点。进程控制的原始命令都存在于“thread”命令下: (lldb) thread continue Resuming thread 0x2c03 in process 46915 Resuming process 46915 (lldb)
步进命令 (lldb) thread step-in // The same as gdb’s “step” or “s” (lldb) thread step-over // The same as gdb’s “next” or “n” (lldb) thread step-out // The same as gdb’s “finish” or “f”
逐步指令版本: (lldb) thread step-inst // The same as gdb’s “stepi” / “si” (lldb) thread step-over-inst // The same as gdb’s “nexti” / “ni”
voidcatchMACHExceptions(){ kern_return_t rc = 0; exception_mask_t excMask = EXC_MASK_BAD_ACCESS | EXC_MASK_BAD_INSTRUCTION | EXC_MASK_ARITHMETIC | EXC_MASK_SOFTWARE | EXC_MASK_BREAKPOINT; rc = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &myExceptionPort); if (rc != KERN_SUCCESS) { fprintf(stderr, "------->Fail to allocate exception port\\\\\\\\n"); return; } rc = mach_port_insert_right(mach_task_self(), myExceptionPort, myExceptionPort, MACH_MSG_TYPE_MAKE_SEND); if (rc != KERN_SUCCESS) { fprintf(stderr, "-------->Fail to insert right"); return; } rc = thread_set_exception_ports(mach_thread_self(), excMask, myExceptionPort, EXCEPTION_DEFAULT, MACHINE_THREAD_STATE); if (rc != KERN_SUCCESS) { fprintf(stderr, "-------->Fail to set exception\\\\\\\\n"); return; } // at the end of catchMachExceptions, spawn the exception handling thread pthread_t thread; pthread_create(&thread, NULL, exc_handler, NULL); } // end catchMACHExceptions
staticvoid *exc_handler(void *ignored){ // Exception handler – runs a message loop. Refactored into a standalone function // so as to allow easy insertion into a thread (can be in same program or different) mach_msg_return_t rc; fprintf(stderr, "Exc handler listening\\\\\\\\n"); // The exception message, straight from mach/exc.defs (following MIG processing) // copied here for ease of reference. typedefstruct { mach_msg_header_t Head; /* start of the kernel processed data */ mach_msg_body_t msgh_body; mach_msg_port_descriptor_t thread; mach_msg_port_descriptor_t task; /* end of the kernel processed data */ NDR_record_t NDR; exception_type_t exception; mach_msg_type_number_t codeCnt; integer_t code[2]; int flavor; mach_msg_type_number_t old_stateCnt; natural_t old_state[144]; } Request; Request exc;
structrep_msg { mach_msg_header_t Head; NDR_record_t NDR; kern_return_t RetCode; } rep_msg; for(;;) { // Message Loop: Block indefinitely until we get a message, which has to be // 这里会阻塞,直到接收到exception message,或者线程被中断。 // an exception message (nothing else arrives on an exception port) rc = mach_msg( &exc.Head, MACH_RCV_MSG|MACH_RCV_LARGE, 0, sizeof(Request), myExceptionPort, // Remember this was global – that's why. MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); if(rc != MACH_MSG_SUCCESS) { /*... */ break ; };
// Normally we would call exc_server or other. In this example, however, we wish // to demonstrate the message contents: printf("Got message %d. Exception : %d Flavor: %d. Code %lld/%lld. State count is %d\\\\\\\\n" , exc.Head.msgh_id, exc.exception, exc.flavor, exc.code[0], exc.code[1], // can also print as 64-bit quantity exc.old_stateCnt); rep_msg.Head = exc.Head; rep_msg.NDR = exc.NDR; rep_msg.RetCode = KERN_FAILURE; kern_return_t result; if (rc == MACH_MSG_SUCCESS) { result = mach_msg(&rep_msg.Head, MACH_SEND_MSG, sizeof (rep_msg), 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); } } returnNULL; } // end exc_handler
除了上面硬件产生的信号,另外还有软件产生的信号。软件产生的信号来自kill()、pthread_kill()两个函数的调用,大概过程是这样的:kill()/pthread_kill() –> … –> psignal_internal() –> act_set_astbsd()。最终也会调用act_set_astbsd()发送信号到目标线程。这意味着Mach exception流程是不会走的。 另外,在abort()源码注释着:<rdar://problem/7397932> abort() should call pthread_kill to deliver a signal to the aborting thread , 它是这样调用的(void)pthread_kill(pthread_self(), SIGABRT);。Apple’s Crash Reporter 把SIGABRT的Mach exception type记为EXC_CRASH,不同与上面转变表。
当内存对象映射到虚拟地址空间的范围时,将用数据填充虚拟地址空间的范围。地址空间中的所有数据最终都是通过内存对象提供的。Mach在物理内存中建立页面时,向内存对象(分页器)的所有者询问页面的内容,并在回收页面之前将可能修改过的数据返回给分页器。OS X包含两个内置分页器——默认分页器和vnode分页器(default pager and the vnode pager)。
从OS X v10.1开始,EMMI系统得到了增强,以支持“无端口”EMMI。在传统的EMMI中,为每个内存区域创建两个Mach端口,同样也为每个缓存的vnode创建两个端口。在最初的实现中,无端口的EMMI用直接内存引用(基本上是指针)替换了这一点。在将来的版本中,端口将用于与内核外部的分页器通信,同时使用直接引用与驻留在内核空间中的分页器通信。这些更改的最终结果是,早期版本的无端口EMMI不支持运行在内核空间之外的分页器。这种支持有望在未来的版本中恢复。
structipc_port { /* * Initial sub-structure in common with ipc_pset * First element is an ipc_object second is a * message queue */ structipc_objectip_object; structipc_mqueueip_messages; natural_t ip_sprequests:1, /* send-possible requests outstanding */ ip_spimportant:1, /* ... at least one is importance donating */ ip_impdonation:1, /* port supports importance donation */ ip_tempowner:1, /* dont give donations to current receiver */ ip_guarded:1, /* port guarded (use context value as guard) */ ip_strict_guard:1, /* Strict guarding; Prevents user manipulation of context values directly */ ip_reserved:2, ip_impcount:24; /* number of importance donations in nested queue */ union { structipc_space *receiver; structipc_port *destination; ipc_port_timestamp_t timestamp; } data; union { ipc_kobject_t kobject; ipc_importance_task_t imp_task; uintptr_t alias; } kdata; structipc_port *ip_nsrequest; structipc_port *ip_pdrequest; structipc_port_request *ip_requests; structipc_kmsg *ip_premsg; mach_vm_address_t ip_context; mach_port_mscount_t ip_mscount; mach_port_rights_t ip_srights; mach_port_rights_t ip_sorights; #if MACH_ASSERT #define IP_NSPARES 4 #define IP_CALLSTACK_MAX 16 /* queue_chain_t ip_port_links;*//* all allocated ports */ thread_t ip_thread; /* who made me? thread context */ unsignedlong ip_timetrack; /* give an idea of "when" created */ uintptr_t ip_callstack[IP_CALLSTACK_MAX]; /* stack trace */ unsignedlong ip_spares[IP_NSPARES]; /* for debugging */ #endif/* MACH_ASSERT */ } __attribute__((__packed__));
structprocessor { queue_chain_t processor_queue;/* idle/active queue link, * MUST remain the first element */ int state; /* See below */ boolean_t is_SMT; boolean_t is_recommended; structthread *active_thread, /* threadrunningonprocessor */ *next_thread, /* nextthreadwhendispatched */ *idle_thread;/* this processor's idle thread. */ processor_set_t processor_set; /* assigned set */ int current_pri; /* priority of current thread */ sched_mode_t current_thmode; /* sched mode of current thread */ sfi_class_id_t current_sfi_class; /* SFI class of current thread */ int cpu_id; /* platform numeric id */ timer_call_data_t quantum_timer; /* timer for quantum expiration */ uint64_t quantum_end; /* time when current quantum ends */ uint64_t last_dispatch; /* time of last dispatch */ uint64_t deadline; /* current deadline */ boolean_t first_timeslice; /* has the quantum expired since context switch */ #if defined(CONFIG_SCHED_TRADITIONAL) || defined(CONFIG_SCHED_MULTIQ) structrun_queuerunq;/* runq for this processor */ #endif #if defined(CONFIG_SCHED_TRADITIONAL) int runq_bound_count; /* # of threads bound to this processor */ #endif #if defined(CONFIG_SCHED_GRRR) structgrrr_run_queuegrrr_runq;/* Group Ratio Round-Robin runq */ #endif processor_t processor_primary; /* pointer to primary processor for * secondary SMT processors, or a pointer * to ourselves for primaries or non-SMT */ processor_t processor_secondary; structipc_port * processor_self;/* port for operations */ processor_t processor_list; /* all existing processors */ processor_data_t processor_data; /* per-processor data */ };
structprocessor_set { queue_head_t active_queue; /* active processors */ queue_head_t idle_queue; /* idle processors */ queue_head_t idle_secondary_queue; /* idle secondary processors */ int online_processor_count; int cpu_set_low, cpu_set_hi; int cpu_set_count; #if __SMP__ decl_simple_lock_data(,sched_lock) /* lock for above */ #endif #if defined(CONFIG_SCHED_TRADITIONAL) || defined(CONFIG_SCHED_MULTIQ) structrun_queuepset_runq;/* runq for this processor set */ #endif #if defined(CONFIG_SCHED_TRADITIONAL) int pset_runq_bound_count; /* # of threads in runq bound to any processor in pset */ #endif /* CPUs that have been sent an unacknowledged remote AST for scheduling purposes */ uint64_t pending_AST_cpu_mask; #if defined(CONFIG_SCHED_DEFERRED_AST) /* * A seperate mask, for ASTs that we may be able to cancel. This is dependent on * some level of support for requesting an AST on a processor, and then quashing * that request later. * * The purpose of this field (and the associated codepaths) is to infer when we * no longer need a processor that is DISPATCHING to come up, and to prevent it * from coming out of IDLE if possible. This should serve to decrease the number * of spurious ASTs in the system, and let processors spend longer periods in * IDLE. *\/ uint64_t pending_deferred_AST_cpu_mask; #endif struct ipc_port * pset_self; /* port for operations */ structipc_port * pset_name_self;/* port for information */ processor_set_t pset_list; /* chain of associated psets */ pset_node_t node; };
虽然默认情况下用户进程不像Mac OS 9那样共享内存,但应用程序之间的通信(甚至内存共享)仍然是可能的。例如,内核提供了一组丰富的原语,允许进程之间共享一些信息。这些基本类型包括共享库、框架和POSIX共享内存。Mach消息传递提供了另一种方法,将内存从一个进程传递到另一个进程。然而,与Mac OS 9不同的是,如果没有程序员的显式操作,内存共享就无法实现。
达尔文操作系统
OS X内核是一个开源项目。内核以及OS X的其他核心部分统称为Darwin。Darwin是一个完整的操作系统,基于与OS x相同的许多技术。但是,Darwin不包括Apple专有的图形或应用程序层,比如Quartz、QuickTime、Cocoa、Carbon或OpenGL。
OS X网络利用BSD的高级网络功能来提供对现代特性的支持,比如网络地址转换(NAT)和防火墙。网络组件提供
4.4BSD TCP/IP栈和套接字api
同时支持IP和DDP (AppleTalk传输)
multihoming
路由
多播支持
服务器调优
信息包过滤
Mac OS经典支持(通过过滤器)
有关网络的更多信息可以在网络体系结构一章中找到。
文件系统
OS X支持多种类型的文件系统,包括HFS、HFS+、UFS、NFS、ISO 9660等。默认的文件系统类型是HFS+;OS X引导(和“根”)来自HFS+、UFS、ISO、NFS和UDF。OS X文件系统的高级功能包括一个增强的虚拟文件系统(VFS)设计。VFS提供了分层的体系结构(文件系统是可堆叠的)。文件系统组件提供