溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

iOS Mach異常和signal信號分析

發布時間:2021-11-12 16:27:44 來源:億速云 閱讀:210 作者:iii 欄目:移動開發

這篇文章主要講解了“iOS Mach異常和signal信號分析”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“iOS Mach異常和signal信號分析”吧!


1. iOS Mach異常 

1.1 XNU 

Darwin是Mac OS和iOS的操作系統,而XNU是Darwin操作系統的內核部分。XNU是混合內核,兼具宏內核和微內核的特性,而Mach即為其微內核。 

Darwin操作系統和MacOS、iOS系統版本號的對應如上圖所示,Mac可執行下述命令查看Darwin版本號。 

system_profiler SPSoftwareDataType 

1.2 Mach 

Mach:[m?k],操作系統微內核,是許多新操作系統的設計基礎。 

Mach微內核中有幾個基礎概念: 
Tasks,擁有一組系統資源的對象,允許"thread"在其中執行。 
Threads,執行的基本單位,擁有task的上下文,并共享其資源。 
Ports,task之間通訊的一組受保護的消息隊列;task可對任何port發送/接收數據。 
Message,有類型的數據對象集合,只可以發送到port。 

1.3 模擬Mach Message發送 

  ● Mach提供少量API,蘋果文檔介紹較少。 

// 內核中創建一個消息隊列,獲取對應的port 
mach_port_allocate(); 
// 授予task對port的指定權限 
mach_port_insert_right(); 
// 通過設定參數:MACH_RSV_MSG/MACH_SEND_MSG用于接收/發送mach message 
mach_msg(); 

下述代碼模擬向Mach Port發送Message,接收Message后做處理: 
  ● 首先調用createPortAndAddListener創建Mach Port; 
  ● 調用sendMachPortMessage:向已創建的Mach Port發送消息; 
  ● 執行結果示例: 
2018-02-27 09:33:37.797435+0800 xxx[54456:5198921] create a port: 41731 
2018-02-27 09:33:37.797697+0800 xxx[54456:5198921] Send a mach message: [100]. 
2018-02-27 09:33:37.797870+0800 xxx[54456:5199525] Receive a mach message:[100], remote_port: 0, local_port: 41731, exception code: 28672 
  ● 示例代碼: 
// 創建Mach Port并監聽消息 
+ (mach_port_t)createPortAndAddListener { 
    mach_port_t server_port; 
    kern_return_t kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &server_port); 
    assert(kr == KERN_SUCCESS); 
    NSLog(@"create a port: %d", server_port); 

    kr = mach_port_insert_right(mach_task_self(), server_port, server_port, MACH_MSG_TYPE_MAKE_SEND); 
    assert(kr == KERN_SUCCESS); 

    [self setMachPortListener:server_port]; 

    return server_port; 


+ (void)setMachPortListener:(mach_port_t)mach_port { 
  dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 
      mach_message mach_message; 

      mach_message.Head.msgh_size = 1024; 
      mach_message.Head.msgh_local_port = server_port; 

      mach_msg_return_t mr; 

      while (true) { 
          mr = mach_msg(&mach_message.Head, 
                        MACH_RCV_MSG | MACH_RCV_LARGE, 
                        0, 
                        mach_message.Head.msgh_size, 
                        mach_message.Head.msgh_local_port, 
                        MACH_MSG_TIMEOUT_NONE, 
                        MACH_PORT_NULL); 

          if (mr != MACH_MSG_SUCCESS && mr != MACH_RCV_TOO_LARGE) { 
              NSLog(@"error!"); 
          } 

          mach_msg_id_t msg_id = mach_message.Head.msgh_id; 
          mach_port_t remote_port = mach_message.Head.msgh_remote_port; 
          mach_port_t local_port = mach_message.Head.msgh_local_port; 

          NSLog(@"Receive a mach message:[%d], remote_port: %d, local_port: %d, exception code: %d", 
                msg_id, 
                remote_port, 
                local_port, 
                mach_message.exception); 

          abort(); 
      } 
  }); 


// 向指定Mach Port發送消息 
+ (void)sendMachPortMessage:(mach_port_t)mach_port { 
    kern_return_t kr; 
    mach_msg_header_t header; 
    header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0); 
    header.msgh_size = sizeof(mach_msg_header_t); 
    header.msgh_remote_port = mach_port; 
    header.msgh_local_port = MACH_PORT_NULL; 
    header.msgh_id = 100; 

    NSLog(@"Send a mach message: [%d].", header.msgh_id); 

    kr = mach_msg(&header, 
                  MACH_SEND_MSG, 
                  header.msgh_size, 
                  0, 
                  MACH_PORT_NULL, 
                  MACH_MSG_TIMEOUT_NONE, 
                  MACH_PORT_NULL); 


1.4 捕獲Mach異常 
  ● task_set_exception_ports() 設置內核接收Mach異常消息的Port,替換為自定義的Port后,即可捕獲程序執行過程中產生的異常消息。 
  ● 執行結果示例: 
2018-02-27 09:52:11.483076+0800 xxx[55018:5253531] create a port: 23299 
2018-02-27 09:52:14.484272+0800 xxx[55018:5253531] ********** Make a [BAD MEM ACCESS] now. ********** 
2018-02-27 09:52:14.484477+0800 xxx[55018:5253611] Receive a mach message:[2405], remote_port: 23555, local_port: 23299, exception code: 1 
  ● 示例代碼: 
+ (void)createAndSetExceptionPort { 
    mach_port_t server_port; 
    kern_return_t kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &server_port); 
    assert(kr == KERN_SUCCESS); 
    NSLog(@"create a port: %d", server_port); 

    kr = mach_port_insert_right(mach_task_self(), server_port, server_port, MACH_MSG_TYPE_MAKE_SEND); 
    assert(kr == KERN_SUCCESS); 

    kr = task_set_exception_ports(mach_task_self(), EXC_MASK_BAD_ACCESS | EXC_MASK_CRASH, server_port, EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES, THREAD_STATE_NONE); 

    [self setMachPortListener:server_port]; 


// 構造BAD MEM ACCESS Crash 
- (void)makeCrash { 
  NSLog(@"********** Make a [BAD MEM ACCESS] now. **********"); 
  *((int *)(0x1234)) = 122; 


1.5 Runloop 

Mach Port的應用不止于內核級別,在Cocoa Foundation和Core Foundation層同樣有其應用,比如說:Runloop。 

Runloop sources分兩類: 
1.Input sources 
Port-Based sources 
Custom Input sources 

2.Timer sources 
其中Port-Based sources即基于Mach Port,在Runloop中完成消息傳遞。 
上述的Mach API為內核層透出接口,Cocoa Foundation和Core Foundation層分別封裝了Mach Port的接口供調用,參考:Apple - Runloop Programming Guard,有詳細的示例代碼。 

2. signal信號 

signal是一種軟中斷信號,提供異步事件處理機制。signal是進程間相互傳遞信息的一種粗糙方法,使用場景: 
進程終止相關; 
終端交互; 
編程錯誤或硬件錯誤相關,系統遇到不可恢復的錯誤時觸發崩潰機制讓程序退出,比如:除0、內存寫入錯誤等。 
這里我們主要考慮系統遇到不可恢復的錯誤時即Crash時,信號相關的應用。signal信號處理是UNIX操作系統機制,所以Android平臺理論上也是使用的,可以基于signal來捕獲Android Native Crash。 

2.1 signal注冊和處理 
signal() 
   #import<sys/signal.h>; 

注冊signal handler; 
調用成功時,會移除signo信號當前的操作,以handler指定的新信號處理程序替代; 
信號處理函數返回void,因為沒有地方給該函數返回。注冊自定義信號處理函數,構造Crash后,發出信號并執行自定義信號處理邏輯。 

【附】:Xcode Debug運行時,添加斷點,在Crash觸發前,執行pro hand -p true -s false SIGABRT命令。 
(lldb) pro hand -p true -s false SIGABRT 
NAME         PASS   STOP   NOTIFY 
===========  =====  =====  ====== 
SIGABRT      true   false  true 
2018-02-27 12:57:25.284651+0800 xxx[58061:5651844] ********** Make a 'NSRangeException' now. ********** 
2018-02-27 12:57:25.294945+0800 xxx[58061:5651844] *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSSingleObjectArrayI objectAtIndex:]: index 1 beyond bounds [0 .. 0]' 
2018-02-27 12:57:25.888332+0800 xxx[58061:5651844] [signal handler] - handle signal: 6 
  ● 示例代碼: 
// 設置自定義信號處理函數 
+ (void)setSignalHandler { 
    signal(SIGABRT, test_signal_handler); 


static void test_signal_handler(int signo) { 
    NSLog(@"[signal handler] - handle signal: %d", signo); 


// 構造NSRangeException異常,觸發SIGABRT信號發送 
- (void)makeCrash { 
  NSLog(@"********** Make a 'NSRangeException' now. **********"); 
  NSArray *array = @[ @"aaa" ]; 


2.2 LLDB Debugger 

Xcode Debug模式運行App時,App進程signal被LLDB Debugger調試器捕獲;需要使用LLDB調試命令,將指定signal處理拋到用戶層處理,方便調試。 
  ● 查看全部信號傳遞配置: 
// process handle縮寫 
pro hand 
  ● 修改指定信號傳遞配置: 
// option: 
//   -P: PASS 
//   -S: STOP 
//   -N: NOTIFY 
pro hand -option false 信號名 

// 例:SIGABRT信號處理在LLDB不停止,可繼續拋到用戶層 
pro hand -s false SIGABRT 

2.3 可重入 

向內核發送信號時,進程可能執行到代碼的任意位置,例:進程在執行重要操作,中斷后可能產生不一致狀態,或進程正在處理另一信號。因此要確保信號處理程序只執行可重入操作: 
  ● 寫中斷處理程序時,假定中斷進程可能處于不可重入函數中。 
  ● 慎重修改全局數據。 

2.4 高級信號處理 

signal()函數非?;A,只提供了最低限度的信號管理的標準。而sigaction()系統調用,提供更強大的信號管理能力。當信號處理程序運行時,可以用來阻塞特定信號的接收,也可以用來獲取信號發送時各種操作系統和進程狀態的信息。 
  ● 示例代碼: 
// 設置自定義信號處理函數 
+ (void)setSignalHandlerInAdvance { 
    struct sigaction act; 
    // 當sa_flags設為SA_SIGINFO時,設定sa_sigaction來指定信號處理函數 
    act.sa_flags = SA_SIGINFO; 
    act.sa_sigaction = test_signal_action_handler; 
    sigaction(SIGABRT, &act, NULL); 


static void test_signal_action_handler(int signo, siginfo_t *si, void *ucontext) { 
    NSLog(@"[sigaction handler] - handle signal: %d", signo); 

    // handle siginfo_t 
    NSLog(@"siginfo: {\n si_signo: %d,\n si_errno: %d,\n si_code: %d,\n si_pid: %d,\n si_uid: %d,\n si_status: %d,\n si_value: %d\n }", 
          si->si_signo, 
          si->si_errno, 
          si->si_code, 
          si->si_pid, 
          si->si_uid, 
          si->si_status, 
          si->si_value.sival_int); 

感謝各位的閱讀,以上就是“iOS Mach異常和signal信號分析”的內容了,經過本文的學習后,相信大家對iOS Mach異常和signal信號分析這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

亚洲午夜精品一区二区_中文无码日韩欧免_久久香蕉精品视频_欧美主播一区二区三区美女