[
  {
    "path": ".gitignore",
    "content": "# Byte-compiled / optimized / DLL files\n__pycache__/\n*.py[cod]\n*$py.class\n\n# C extensions\n*.so\n\n# Distribution / packaging\n.Python\nbuild/\ndevelop-eggs/\ndist/\ndownloads/\neggs/\n.eggs/\nlib/\nlib64/\nparts/\nsdist/\nvar/\nwheels/\npip-wheel-metadata/\nshare/python-wheels/\n*.egg-info/\n.installed.cfg\n*.egg\nMANIFEST\n\n# PyInstaller\n#  Usually these files are written by a python script from a template\n#  before PyInstaller builds the exe, so as to inject date/other infos into it.\n*.manifest\n*.spec\n\n# Installer logs\npip-log.txt\npip-delete-this-directory.txt\n\n# Unit test / coverage reports\nhtmlcov/\n.tox/\n.nox/\n.coverage\n.coverage.*\n.cache\nnosetests.xml\ncoverage.xml\n*.cover\n*.py,cover\n.hypothesis/\n.pytest_cache/\n\n# Translations\n*.mo\n*.pot\n\n# Django stuff:\n*.log\nlocal_settings.py\ndb.sqlite3\ndb.sqlite3-journal\n\n# Flask stuff:\ninstance/\n.webassets-cache\n\n# Scrapy stuff:\n.scrapy\n\n# Sphinx documentation\ndocs/_build/\n\n# PyBuilder\ntarget/\n\n# Jupyter Notebook\n.ipynb_checkpoints\n\n# IPython\nprofile_default/\nipython_config.py\n\n# pyenv\n.python-version\n\n# pipenv\n#   According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.\n#   However, in case of collaboration, if having platform-specific dependencies or dependencies\n#   having no cross-platform support, pipenv may install dependencies that don't work, or not\n#   install all needed dependencies.\n#Pipfile.lock\n\n# PEP 582; used by e.g. github.com/David-OConnor/pyflow\n__pypackages__/\n\n# Celery stuff\ncelerybeat-schedule\ncelerybeat.pid\n\n# SageMath parsed files\n*.sage.py\n\n# Environments\n.env\n.venv\nenv/\nvenv/\nENV/\nenv.bak/\nvenv.bak/\n\n# Spyder project settings\n.spyderproject\n.spyproject\n\n# Rope project settings\n.ropeproject\n\n# mkdocs documentation\n/site\n\n# mypy\n.mypy_cache/\n.dmypy.json\ndmypy.json\n\n# Pyre type checker\n.pyre/\n"
  },
  {
    "path": "README.md",
    "content": "# lldbTrace\n\n##### How to use it?\n\n> 1.*Break at an address where you want to begin tracing.*\n>\n> ![](https://github.com/yangyss/lldb-trace/blob/script/source/1111.png)\n>\n> 2, *Import lldb python script.*\n>\n> ![](https://github.com/yangyss/lldb-trace/blob/script/source/2222.png)\n>\n> 3,*Use 'trace' command,and set end tracing addresses.Multi-address split by \";\".*\n>\n> ![](https://github.com/yangyss/lldb-trace/blob/script/source/3333.png)\n>\n> 4,*Result  like  ...*\n>\n> ![](https://github.com/yangyss/lldb-trace/blob/script/source/4444.png)\n\n\n\n> *参考：https://github.com/gm281/lldb-trace*\n\n"
  },
  {
    "path": "lldbTrace.py",
    "content": "#!/usr/bin/python3\n# -*- encoding: utf-8 -*-\n#@File    :   lldb-trace.py\n#@Time    :   2021/06/25 22:16:01\n#@Author  :   wt \n\nimport re\nimport lldb\nimport shlex\nimport optparse\nimport threading\nimport ctypes\nimport os\n \n\n\nlog_default_path = '~/Desktop/' # 默认路径 , \n\noptions = None\nd_log_file = None   # fileName : Redirect debug log in d_log_file\nd_log_file_name = None\nt_log_file = None   # fileName : Redirect trace log in t_log_file\nt_log_file_name = None\nt_only_self_module = None \nt_parser_msgsend_parameters = None\nASLR = None\nnum_for_print_progress = 500 # 进度条\n\ndef log_d(msg): # debug log\n    global d_log_file,options\n    if options.log_type == 'debug':\n        d_log_file.write(msg)\n        d_log_file.write('\\n')\n\ndef log_t(msg): # trace log\n    global t_log_file\n    t_log_file.write(msg)\n    t_log_file.write('\\n')\n\ndef log_c(msg): # console log\n    global options\n    if options.print_tracing_progress:\n        print(msg)\n    \ndef log_flush():\n    global d_log_file,t_log_file\n    if d_log_file is not None:\n        d_log_file.flush()\n    if t_log_file is not None:\n        t_log_file.flush()\n\ndef dlog(msg):\n    print(\"xxxxxxxxx-> {}\".format(msg))\n\n# 调试类型\nTRACE_TYPE_Instrument = 0,\nTRACE_TYPE_Function = 1,\n# 设备架构 \nDEVICE_BSD32 = 'BSD32'\nDEVICE_BSD64 = 'BSD64'\nDEVICE_Arm64 = 'Arm64'\nDEVICE_x8664 = 'x86-64'\nDEVICE_x8632 = 'x86-32'\n# 调试中需要处理的 汇编指令信息\nCONST_INS_call = 'call',\nCONST_INS_jmp = 'jmp',\nCONST_INS_condition_jmp = 'condition_jmp',\nCONST_INS_syscall = 'syscall',\nCONST_INS_end = 'func_end_mnemonic'\nCONST_FUNC_NAME_ignore_list = 'ignore_func_name_list'\nCONST_FUNC_NAME_protect_list = 'protect_func_name_list'\nCONST_PRINT_obj = 'obj'\nCONST_PRINT_char_star = 'char_star'\nCONST_REGISTER_re = 're'\nCONST_REGISTER_default_return_register = 'default_return_register'\n\n\n# 断点列表里的 key \nCONST_BREAKPOINT_BREAKPOINE = 'breakpoint',\nCONST_BREAKPOINT_INDEX = 'index',  # 引用计数\n\n# deal_with 的 返回值\nCONST_DEAL_WITH_error = 0,\nCONST_DEAL_WITH_continue = 1,\nCONST_DEAL_WITH_wait_breakpoint = 2,\nCONST_DEAL_WITH_break = 3,\n# check ins end type\nCONST_CHECK_ins_default = 0\nCONST_CHECK_ins_ret = 1\nCONST_CHECK_ins_end_address =2\n\n\n#########################################################\nCONST_DEVICE_info_list = {\n    DEVICE_BSD64 : {\n        CONST_FUNC_NAME_ignore_list : ['printf','objc_unsafeClaimAutoreleasedReturnValue','objc_storeStrong'],\n        CONST_FUNC_NAME_protect_list : {\n            'objc_msgSend' : {\n                # if trace function,need to analyse parameters. if parser_msgsend_parameters was true, need to analyse parameters too.\n                CONST_PRINT_obj:['po [$x0 class]'],\n                CONST_PRINT_char_star:['x1']\n            }\n        },\n        CONST_REGISTER_re : [r'\\b[xwd][0-9]{1,2}',r'\\b[xwd][0-9]{1,2},',r'sp'], # r'\\b[xw][0-9]{1,2}[,]{0,1}'\n        CONST_REGISTER_default_return_register:'x0',\n\n        CONST_INS_call : ['bl'],#,'bl',\n        CONST_INS_jmp  : ['cb','b','tb'],#'b',\n        CONST_INS_condition_jmp : ['b'],\n        CONST_INS_syscall : ['svc'],#'svc'\n        CONST_INS_end : ['ret']\n    },\n    DEVICE_Arm64 : {},\n    DEVICE_x8664 : {},\n    DEVICE_x8632 : {}\n}\n#########################################################\n# 当前设备类型\nDEVICE = DEVICE_BSD64\n#########################################################\n\n\nclass WTListeningThread(threading.Thread):\n    def __init__(self, wait_event, notify_event,listener,process):\n        super(WTListeningThread, self).__init__()\n        self.wait_event = wait_event\n        self.notify_event = notify_event\n        self.listener = listener\n        self.process = process\n        self.exiting = False\n        self.wait_timeout = False\n\n    def wait_timed_out(self):\n        return self.wait_timeout\n\n    def exit(self):\n        self.exiting = True\n\n    def run(self):\n        steam :lldb.SBStream = lldb.SBStream()\n        while True:\n            self.wait_event.wait()\n            self.wait_event.clear()\n            if self.exiting:\n                log_d('=>>>Listener thread was asked to exit, complying')\n                self.notify_event.set()\n                return\n            while True:\n                event = lldb.SBEvent()\n                steam.Clear()\n                log_d('=>>>Listener waiting for events')\n                wait_result = self.listener.WaitForEvent(10, event)\n                event.GetDescription(steam)\n                log_d('=>>>Listener wait exited: {}, {}'.format(str(wait_result), steam.GetData()))\n\n                if not wait_result:\n                    log_d('=>>>Listener thread timed out waiting for notification')\n                    self.wait_timeout = True\n                    self.notify_event.set()\n                    break\n                processState = self.process.GetState()\n                if processState == lldb.eStateStopped:\n                    log_d('=>>>Listener detected process state change, but it is not stopped: {}'.format(str(processState)))\n                    break\n                log_d('=>>>Process not stopped, listening for the next event')\n            log_d('=>>>Listener thread got event, notifying')\n            self.notify_event.set()\n\ndef get_c_char_star(address):\n    retstr = ''\n    curr_addr = address\n    while True:\n        p = ctypes.cast(curr_addr,ctypes.POINTER(ctypes.c_char))\n        value = p.contents.value\n        if not (value[0] == 0) :\n            retstr = retstr + chr(value[0])\n            curr_addr = curr_addr + 1\n        else:\n            break\n    return retstr\n\ndef handle_command(command,debugger:lldb.SBDebugger):\n    log_d('handle_command -> command : {}'.format(command))\n    interpreter:lldb.SBCommandInterpreter = debugger.GetCommandInterpreter()\n    re_obj:lldb.SBCommandReturnObject = lldb.SBCommandReturnObject()\n    interpreter.HandleCommand(command,re_obj)\n    result = ''\n    log_d('handle_command -> re_obj status : {}'.format(re_obj.GetStatus()))\n    if re_obj.GetStatus() == lldb.eReturnStatusSuccessFinishResult:\n        result = re_obj.GetOutput()\n    # print('|{}|'.format(result.replace('\\n','')))\n    return result.replace('\\n','')\n\ndef continue_and_wait_for_breakpoint(process, thread, listening_thread, wait_event, notify_event):\n    wait_event.set()\n    log_d(\"Process in state: {}\".format(str(process.GetState())))\n    process.Continue()\n    log_d('Process continued, waiting for notification')\n    notify_event.wait()\n    notify_event.clear()\n    log_d('Got notification, process in state: {}, sanity checks follow'.format(str(process.GetState())))\n    if listening_thread.wait_timed_out():\n        log_d('Listener thread exited unexpectedly')\n        return False\n    if thread.GetStopReason() != lldb.eStopReasonBreakpoint:\n        log_d(\"Thread {} didn't stop due to a breakpoint\".format(str(thread)))\n        return False\n    return True\n\ndef suspend_threads_escape_select_thread(process:lldb.SBProcess,flag:bool):\n    select_thread :lldb.SBThread = process.GetSelectedThread()\n    if flag :\n        for item in process:\n            if select_thread.GetThreadID() == item.GetThreadID():\n                log_d('current run thread : {}'.format(item))\n            else:\n                log_d('Suspend thread : {}'.format(item))\n                item.Suspend()\n    else:\n        log_d('Resume all threads.')\n        for item in process:\n            item.Resume()\n    \n            \n\ndef match_registers(text):\n    now_list = []\n    fileters = CONST_DEVICE_info_list[DEVICE][CONST_REGISTER_re]\n    for item in fileters:\n        find_result = re.finditer(item,text)\n        match : str = ''\n        for match in find_result:\n            tmpStr = '{}'.format(match.group())\n            if tmpStr.find(',') >= 0 :\n                if not(tmpStr[:-1] in now_list) :\n                    now_list.append(tmpStr[:-1])\n            else:\n                if not(tmpStr in now_list):\n                    now_list.append(tmpStr)\n    return now_list\n\nclass WTInstruction():\n    def __init__(self, target, thread, frame,debugger,traceType=TRACE_TYPE_Instrument,traceMsgSend=False,endAddress=None):\n        self.target:lldb.SBTarget = target\n        self.thread:lldb.SBThread = thread\n        self.frame:lldb.SBFrame = frame\n        self.debugger:lldb.SBDebugger = debugger\n\n        self.trace_type = traceType      # Trace 类型\n\n        self.next_instruction:lldb.SBInstruction = None   # 下一条 instruction\n        self.current_instruction:lldb.SBInstruction = None # 当前 instruction\n        self.last_instruction:lldb.SBInstruction = None # 上一条 instruction\n\n        self.begin_trace_address = None  # 开始 Trace 地址\n        self.end_trace_address = []\n\n        for item in re.split(';',endAddress):\n            self.end_trace_address.append(int(item,16)) # 结束 Trace 地址\n\n        # 包含 breakpoint : 以及 引用计数 used_num :\n        self.breakpoint_list = {}   # 所有断点 的 list\n        self.current_instruction_list = {} # 当前 symbol 下的 所有的 instruction 列表\n        self.current_instruction_end_address_list = [] # 当前 symbol 下的 所有的  end_address 列表\n        self.call_return_instruction_list = {} # tracing 中，所有函数返回的地址 列表\n\n        self.current_module_name:str = None # 当前模块\n\n        self.append_msg = '' # 附加消息\n\n        self.print_index = 0\n        self.print_text = '    '\n\n    def increase_print_index(self):\n        log_d('@@@@ increase print index. {} : {}'.format(self.print_index,self.print_index + 1))\n        self.print_index = self.print_index + 1\n        \n    \n    def check_in_call_return_instruction_list(self):\n        pc = self.get_current_pc()\n        if pc in self.call_return_instruction_list:\n            log_d('@@@@ {} in call_return_instruction_list'.format(hex(pc)))\n            return True\n        log_d('@@@@ {} not in call_return_instruction_list'.format(hex(pc)))\n        return False\n\n    def decrease_print_index(self):\n        log_d('@@@@ decrease print index. {} : {}'.format(self.print_index,self.print_index - 1))\n        self.print_index = self.print_index - 1\n\n    def check_str_in_arr(self,cur_str:str,cur_arr):\n        for item in cur_arr:\n            if cur_str.startswith(item):\n                return True\n        return False\n\n    def init_env(self):\n\n        frame :lldb.SBFrame = self.thread.GetSelectedFrame()\n        symbol:lldb.SBSymbol = frame.GetSymbol()\n\n        if self.current_module_name is None:\n            self.current_module_name:str = '{}'.format(self.frame.GetModule())\n            log_d('current module name : {}'.format(self.current_module_name))\n\n        \n        instructionlist : lldb.SBInstructionList = symbol.GetInstructions(self.target)\n        # 清空 current_instruction_list  和 current_instruction_end_address_list\n        if self.current_instruction_list:\n            self.current_instruction_list = {}\n            self.current_instruction_end_address_list = []\n            \n        # endaddress 加入到 end tracing 地址列表中\n        cur_end_address = symbol.GetEndAddress().GetLoadAddress(self.target) - 4\n        self.end_trace_address.append(cur_end_address)   \n        \n        # 把 返回指令的 地址 加入到 end tracing 地址列表中\n        instruction :lldb.SBInstruction = None\n        for instruction in instructionlist:\n            address :lldb.SBAddress = instruction.GetAddress()\n            cur_mnemonic:str = instruction.GetMnemonic(self.target)\n            load_address = address.GetLoadAddress(self.target)\n            if self.check_str_in_arr(cur_mnemonic,CONST_DEVICE_info_list[DEVICE][CONST_INS_end]):\n                if not load_address in self.end_trace_address:\n                    self.end_trace_address.append(load_address)\n\n\n    # 获得当前 pc\n    def get_current_pc(self):\n        now_frame :lldb.SBFrame = self.thread.GetSelectedFrame()\n        if now_frame:\n            return now_frame.GetPC()\n        return None\n\n    # 判断当前 pc 是否在 list 中\n    # 不在的话，更新所有 list\n    def checkPCInList_transferCurrentSymbolInstrucionsToList(self,address):\n        # current_instruction_list 为空，或者  cur_pc(有效) 不在 current_instruction_list 里\n        if not self.current_instruction_list or (address and (not (address in self.current_instruction_list))) :\n            frame :lldb.SBFrame = self.thread.GetSelectedFrame()\n            symbol:lldb.SBSymbol = frame.GetSymbol()\n            ################## 给 current_instruction_end_address_list 赋值\n            # 获得 当前 symbol 下的 endAddress\n            cur_end_address = symbol.GetEndAddress().GetLoadAddress(self.target) - 4\n            log_d('cur symbol end addr : {}'.format(hex(cur_end_address)))\n            self.current_instruction_end_address_list = []\n            # 把 结束地址，加入到 current_instruction_end_address_list 中\n            self.current_instruction_end_address_list.append(cur_end_address)\n\n            # 给 current_instruction_list 赋值\n            # 获得 当前 symbol 下的 instructionlist\n            instructionlist : lldb.SBInstructionList = symbol.GetInstructions(self.target)\n\n            # 清空 current_instruction_list\n            if self.current_instruction_list:\n                self.current_instruction_list = {}\n                self.current_instruction_end_address_list = {}\n\n            instruction :lldb.SBInstruction = None            \n            # 处理 所有的 instruction，\n            for instruction in instructionlist:\n                address :lldb.SBAddress = instruction.GetAddress()\n                cur_mnemonic:str = instruction.GetMnemonic(self.target)\n                load_address = address.GetLoadAddress(self.target)\n                self.current_instruction_list[load_address] = instruction  \n\n            return False\n        return True\n\n    def updata_instruction_instructionList(self):\n        cur_pc = self.get_current_pc()     \n        self.checkPCInList_transferCurrentSymbolInstrucionsToList(cur_pc)\n\n        if cur_pc in self.current_instruction_list:\n            self.current_instruction = self.current_instruction_list[cur_pc]\n        else:\n            self.current_instruction = None\n\n\n    def clean_env(self):\n        for item in self.breakpoint_list.values():\n            breakpoint :lldb.SBBreakpoint = item[CONST_BREAKPOINT_BREAKPOINE]\n            self.target.BreakpointDelete(breakpoint.GetID())     \n        self.breakpoint_list = {}\n\n\n    def deal_with(self):\n        return self.deal_with_ins()\n\n    def updata_last_instruction(self):\n        self.last_instruction = self.current_instruction\n\n    def get_current_symbol_name(self):\n        frame:lldb.SBFrame = self.thread.GetSelectedFrame()\n        sym:lldb.SBSymbol = frame.GetSymbol()\n        return sym.GetName()\n\n    def get_next_instruction(self):\n        pc = self.get_current_pc()\n        size = self.current_instruction.GetByteSize()\n        next_pc = pc + size\n        self.checkPCInList_transferCurrentSymbolInstrucionsToList(next_pc)\n        if next_pc in self.current_instruction_list:\n            self.next_instruction = self.current_instruction_list[next_pc]\n        else:\n            self.next_instruction = None\n\n    def print_tracing_progress(self,count):\n        # 当前trace的总行数 内存地址:文件地址: <函数名>\n        global ASLR\n        mem_addr = 0\n        file_addr = 0\n        if self.current_instruction:\n            mem_addr = self.current_instruction.GetAddress().GetLoadAddress(self.target)\n        if not (mem_addr == 0) :\n            file_addr = mem_addr - ASLR   \n        out_str = '{: <10}  {} : {} <{}>'.format(count,hex(mem_addr),hex(file_addr),self.get_current_symbol_name())\n        log_c(out_str)\n\n    def log_current_instruction(self,cur_pc):\n        cur_mnemonic:str = self.current_instruction.GetMnemonic(self.target)\n        cur_operands:str = self.current_instruction.GetOperands(self.target)\n        aligns = self.print_text * self.print_index\n        if self.last_instruction:\n            last_mnemonic:str = self.last_instruction.GetMnemonic(self.target)      \n            if self.check_str_in_arr(last_mnemonic,CONST_DEVICE_info_list[DEVICE][CONST_INS_call]) :\n                frame:lldb.SBFrame = self.thread.GetSelectedFrame()\n                return_register = CONST_DEVICE_info_list[DEVICE][CONST_REGISTER_default_return_register]\n                value:lldb.SBValue = frame.FindRegister(return_register)\n                data_str = '{: <3} : {} '.format(return_register,value.GetValue())\n                log_t('{}{: <15}{: <6}{: <30}// {} {}'.format(aligns,hex(cur_pc),cur_mnemonic,cur_operands,data_str,self.append_msg))\n                self.append_msg = ''\n                return  \n            last_operands:str = self.last_instruction.GetOperands(self.target)      \n            register_arr = match_registers(last_operands)\n            data_str = ''\n            for now_reg in register_arr:\n                frame:lldb.SBFrame = self.thread.GetSelectedFrame()\n                value:lldb.SBValue = frame.FindRegister(now_reg)\n                data_str = '{}{: <3} : {} '.format(data_str,now_reg,value.GetValue())\n            \n            log_t('{}{: <15}{: <6}{: <30}// {} {}'.format(aligns,hex(cur_pc),cur_mnemonic,cur_operands,data_str,self.append_msg))\n            self.append_msg = ''\n            return\n        log_t('{}{: <15}{: <6}{: <30} {}'.format(aligns,hex(cur_pc),cur_mnemonic,cur_operands,self.append_msg))\n        self.append_msg = ''\n\n    def parser_ins_symbol_name(self,last_symbole_name:str,cur_symbol_name : str):\n\n        if not cur_symbol_name  or not last_symbole_name:\n            log_d('err : cur_symbol_name or last_symbole_name is None')\n            return True\n\n        if cur_symbol_name in CONST_DEVICE_info_list[DEVICE][CONST_FUNC_NAME_ignore_list]:\n            # 忽略的 符号名\n            log_d('cur_symbol_name in ignore_function_names')\n            return True\n\n        if cur_symbol_name in CONST_DEVICE_info_list[DEVICE][CONST_FUNC_NAME_protect_list]:\n            # # 设置 附加信息 \n            \n            # # log_t('{}<< current frame name >> :  {}'.format(aligens,cur_symbol_name))\n            # frame :lldb.SBFrame = self.thread.GetSelectedFrame()\n            \n            # for pro_key,pro_value in CONST_DEVICE_info_list[DEVICE][CONST_FUNC_NAME_protect_list].items():\n                \n            #     if pro_key == cur_symbol_name:\n\n            #         objs = pro_value[CONST_PRINT_obj]\n            #         char_stars = pro_value[CONST_PRINT_char_star]\n                    \n            #         for char_star_item in char_stars: \n            #             func_name_register:lldb.SBValue = frame.FindRegister(char_star_item)\n            #             addr = int(func_name_register.GetValue(),16)\n                        # self.append_msg = ' : {}{: <3} ==> {} '.format(self.append_msg,char_star_item,get_c_char_star(addr))\n                    \n            #         for obj_item in objs:\n            #             item_value =  handle_command(obj_item,self.debugger)\n            #             self.append_msg = '{}{: <3} ==> {} '.format(self.append_msg,obj_item,item_value)\n\n            #         break\n\n            # log_d('cur_symbol_name in protect_function_names')\n            # return True\n            pass\n\n        return False\n\n    def add_next_breakpoint(self):\n        if self.next_instruction:\n            next_pc = self.next_instruction.GetAddress().GetLoadAddress(self.target)\n            if next_pc in self.breakpoint_list:\n                breakpoint = self.breakpoint_list[next_pc][CONST_BREAKPOINT_BREAKPOINE]\n                log_d('->>> increase index on breakpoint : {}'.format(str(breakpoint)))\n                self.breakpoint_list[next_pc][CONST_BREAKPOINT_INDEX] = self.breakpoint_list[next_pc][CONST_BREAKPOINT_INDEX] + 1\n            else:\n                breakpoint :lldb.SBBreakpoint = self.target.BreakpointCreateByAddress(next_pc)\n                breakpoint.SetThreadID(self.thread.GetThreadID())\n                item = {}\n                item[CONST_BREAKPOINT_BREAKPOINE] = breakpoint\n                item[CONST_BREAKPOINT_INDEX] = 1\n                self.breakpoint_list[next_pc] = item\n                log_d('->>> add address : {}  breakpoint : {}'.format(hex(next_pc),str(breakpoint)))\n    \n    def add_call_return_addr(self):\n        if self.next_instruction:\n            next_pc = self.next_instruction.GetAddress().GetLoadAddress(self.target)\n            log_d('add {} index in call_return_instruction_list.'.format(hex(next_pc)))\n            if next_pc in self.call_return_instruction_list:\n                self.call_return_instruction_list[next_pc] = self.call_return_instruction_list[next_pc] + 1\n            else:\n                self.call_return_instruction_list[next_pc] = 1\n\n    def sub_call_return_addr(self):\n        pc = self.get_current_pc()\n        if pc in self.call_return_instruction_list:\n            log_d('@@@@ delete call return addr : {} out of call_return_instruction_list.'.format(hex(pc)))\n            if self.call_return_instruction_list[pc] > 1:\n                tmp = self.call_return_instruction_list[pc]\n                self.call_return_instruction_list[pc] = tmp - 1\n            else:\n                self.call_return_instruction_list.pop(pc)\n\n\n    def check_need_delete_breakpoint_in_current_call_return_list_and_decrease_index(self,cur_pc):\n        if cur_pc in self.call_return_instruction_list:\n            index = self.call_return_instruction_list[cur_pc]\n            if index > 0 :\n                self.call_return_instruction_list[cur_pc] = index - 1\n                return True\n            else:\n                self.call_return_instruction_list.pop(cur_pc)\n        return False \n\n    def delete_current_breakpoint(self):\n        if self.current_instruction:\n            curr_pc = self.current_instruction.GetAddress().GetLoadAddress(self.target)\n            if not curr_pc in self.breakpoint_list:\n                log_d('->>> {} not in breakpoint_list'.format(hex(curr_pc)))\n                return\n            item = self.breakpoint_list[curr_pc]\n            if not item :\n                log_d('->>> curr address : {} not in breakpoint_list'.format(hex(curr_pc)))\n                return\n            index = item[CONST_BREAKPOINT_INDEX]\n            if index > 1 :\n                log_d('->>> increase index on breakpoint : {}'.format(str(item[CONST_BREAKPOINT_BREAKPOINE])))\n                self.breakpoint_list[curr_pc][CONST_BREAKPOINT_INDEX] = index - 1\n            elif index == 1:\n                delete_breakpoint :lldb.SBBreakpoint = item[CONST_BREAKPOINT_BREAKPOINE]\n                if not self.check_need_delete_breakpoint_in_current_call_return_list_and_decrease_index(curr_pc):\n                    self.target.BreakpointDelete(delete_breakpoint.GetID())\n                    log_d('**** delet breakpoint at : {}'.format(hex(self.get_current_pc())))\n                self.breakpoint_list.pop(curr_pc)\n            else:\n                log_c('->>> {} : breakpoint delete error'.format(hex(curr_pc)))\n                log_d('->>> {} : breakpoint delete error'.format(hex(curr_pc)))\n\n    def check_currentIns_is_endIns(self):\n        if self.current_instruction:\n            size = self.current_instruction.GetByteSize()\n            pc = self.get_current_pc()\n            nextpc = pc + size\n            if nextpc in self.current_instruction_end_address_list:\n                log_d('addr : {} in current_instruction_end_address_list'.format(hex(nextpc)))\n                return True,CONST_CHECK_ins_end_address\n\n            mnemonic:str = self.current_instruction.GetMnemonic(self.target)\n            for ins_end_item in CONST_DEVICE_info_list[DEVICE][CONST_INS_end]:\n                if mnemonic.startswith(ins_end_item):\n                    log_d('addr : {} is CONST_INS_end'.format(hex(pc)))\n                    return True,CONST_CHECK_ins_ret\n            log_d('addr : {} is default ins.'.format(hex(pc)))\n            return False,CONST_CHECK_ins_default\n        else:\n            log_d('warning : current ins is None.')\n            log_c('warning : current ins is None.')\n        return False,CONST_CHECK_ins_default\n\n    def check_ins_call(self,mnemonic:str,cur_symbol:lldb.SBSymbol):\n        for call_item  in CONST_DEVICE_info_list[DEVICE][CONST_INS_call]:\n            if not mnemonic.startswith(call_item):\n                continue\n            pc = self.get_current_pc()\n            self.get_next_instruction() # 获得下一条指令\n            if not self.next_instruction is None:       \n                self.add_next_breakpoint()\n                self.add_call_return_addr()\n\n            last_symbol_name = self.get_current_symbol_name()\n            self.delete_current_breakpoint()# 删除当前断点\n            self.thread.StepInstruction(False) # 单步进入\n            sym_name = self.get_current_symbol_name()\n\n            if self.parser_ins_symbol_name(last_symbol_name,sym_name) :  # 解析 symbol_name\n                self.append_msg = sym_name + self.append_msg\n                self.log_current_instruction(pc)\n                self.increase_print_index()\n                log_d('####### return : check_ins_call. ignore fun or protect fun. value : CONST_DEAL_WITH_wait_breakpoint')\n                return True,CONST_DEAL_WITH_wait_breakpoint\n                \n            self.log_current_instruction(pc) # 打印信息\n            if not(sym_name == last_symbol_name) :\n                if sym_name and (not (sym_name == '')):\n                    log_t('{}{} : '.format(self.print_text * self.print_index,sym_name))\n\n            # 忽略的，保护的，需要  CONST_DEAL_WITH_wait_breakpoint\n            self.increase_print_index()\n\n            log_d('####### return : check_ins_call. value : CONST_DEAL_WITH_continue')\n            return True,CONST_DEAL_WITH_continue\n        \n        return False,None\n\n    def check_ins_jmp(self,mnemonic:str,cur_symbol:lldb.SBSymbol):\n        for jmp_item  in CONST_DEVICE_info_list[DEVICE][CONST_INS_jmp]:\n            if not mnemonic.startswith(jmp_item):\n                continue\n            \n            pc = self.get_current_pc()\n            self.get_next_instruction() # 获得下一条指令\n            if not self.next_instruction is None:       \n                self.add_next_breakpoint()\n\n            last_symbol_name = self.get_current_symbol_name()\n            self.delete_current_breakpoint()\n            self.thread.StepInstruction(False)\n\n            sym_name = self.get_current_symbol_name()\n\n            if sym_name and self.parser_ins_symbol_name(last_symbol_name,sym_name):\n                print('type : {} symName : {}'.format(type(sym_name),sym_name))\n                if self.append_msg == None:\n                    self.append_msg = ''\n                self.append_msg = sym_name + self.append_msg\n                self.log_current_instruction(pc)\n                log_d('####### return : check_ins_jmp. ignore fun or protect fun. value : CONST_DEAL_WITH_wait_breakpoint')\n                return True,CONST_DEAL_WITH_wait_breakpoint\n\n            self.log_current_instruction(pc) # 打印信息\n\n            log_d('####### return : check_ins_jmp. same module. value : CONST_DEAL_WITH_continue')\n            return True,CONST_DEAL_WITH_continue\n        \n        return False,None\n\n    def check_ins_syscall(self,mnemonic:str,cur_symbol:lldb.SBSymbol):\n        for syscall_item in CONST_DEVICE_info_list[DEVICE][CONST_INS_syscall]:\n            if not mnemonic.startswith(syscall_item):\n                continue\n\n\n            self.get_next_instruction() # 获得下一条指令\n            if not self.next_instruction is None:       \n                self.add_next_breakpoint()\n\n            self.delete_current_breakpoint()\n            \n            self.log_current_instruction(self.get_current_pc()) # 打印信息\n            log_d('####### return : check_ins_syscall. value : CONST_DEAL_WITH_wait_breakpoint')\n            return True,CONST_DEAL_WITH_wait_breakpoint\n\n        return False,None\n\n    def check_ins_other(self,cur_symbol:lldb.SBSymbol):\n        self.get_next_instruction() # 获得下一条指令\n        if not self.next_instruction is None:       \n            self.add_next_breakpoint()\n\n        self.delete_current_breakpoint()\n        self.log_current_instruction(self.get_current_pc())        # 打印信息\n\n    def check_out_tracing(self):\n        # 递归函数的处理 。。。。。。。\n            \n        pc = self.get_current_pc()\n        if pc in self.end_trace_address:\n            self.delete_current_breakpoint()\n            self.log_current_instruction(pc)\n            log_d('end trace addr list : {}'.format(self.end_trace_address))\n            log_d('cur pc : {}'.format(pc))\n            return True\n        return False\n\n    def check_end_fun(self):\n        # 当前在结束地址       \n        flag,ret = self.check_currentIns_is_endIns()\n        if flag :\n            if ret == CONST_CHECK_ins_ret:\n                pc = self.get_current_pc()\n                self.delete_current_breakpoint()\n                self.log_current_instruction(pc)\n                log_d('@@@@ check_end_fun : address : {} is ret ins.'.format(hex(pc)))\n                return  True,CONST_DEAL_WITH_wait_breakpoint\n            elif ret == CONST_CHECK_ins_end_address:\n                last_pc = self.get_current_pc()\n                self.thread.StepInstruction(False)\n                self.delete_current_breakpoint()\n                # 判断当前pc 是否在 instructionList中\n                pc = self.get_current_pc()\n                if pc in self.current_instruction_list:\n                    self.log_current_instruction(last_pc)\n                    log_d('@@@@ check_end_fun : address : {} is call end address,and in current_instruction_list.'.format(hex(last_pc)))\n                    return True,CONST_DEAL_WITH_continue\n                else:\n                    # 可以 decrease print index\n                    self.log_current_instruction(last_pc)\n                    log_d('@@@@ check_end_fun : address : {} is call end address,and not in current_instruction_list.'.format(hex(last_pc)))\n                    return True,CONST_DEAL_WITH_wait_breakpoint\n            else:\n                pass\n        log_d('@@@@ check_end_fun : address : {} is not call end address or ret ins.'.format(hex(self.get_current_pc())))\n        return False,None\n\n    def check_symbol_valid(self):\n        now_frame :lldb.SBFrame =  self.thread.GetSelectedFrame()\n        if now_frame:\n            sym:lldb.SBSymbol = now_frame.GetSymbol()\n            if not sym.IsValid():\n                log_d('####### return : check_symbol_valid not valid. value : CONST_DEAL_WITH_wait_breakpoint')\n                return False,CONST_DEAL_WITH_wait_breakpoint\n        log_d('@@@@ check_symbol_valid : valid.')\n        return True,None\n\n    def check_in_module(self):\n        frame :lldb.SBFrame = self.thread.GetSelectedFrame()\n        now_module_name = '{}'.format(frame.GetModule())\n        log_d('@@@@ current module name : {}'.format(now_module_name))\n        if now_module_name == self.current_module_name :\n            return True,None\n        log_d('####### return : check_in_module. is not current module. value : CONST_DEAL_WITH_wait_breakpoint')\n        return False,CONST_DEAL_WITH_wait_breakpoint\n\n\n    def deal_with_ins(self):\n\n        if self.check_in_call_return_instruction_list():\n            self.decrease_print_index()\n            self.sub_call_return_addr()\n\n        # 结束tracing\n        if self.check_out_tracing():\n            log_d('####### return : check_out_tracing value : CONST_DEAL_WITH_break')\n            return CONST_DEAL_WITH_break\n\n        # 函数结束的判断\n        flag,ret = self.check_end_fun()\n        if flag:\n            log_d('####### return : check_end_fun')\n            return ret\n        \n        # frame.GetFunction 和 frame.GetSymbol 是否有效\n        flag,ret = self.check_symbol_valid()\n        if not flag :\n            return ret\n\n        global t_only_self_module\n        if t_only_self_module :\n            flag,ret = self.check_in_module()\n            if not flag:\n                return ret\n        \n        instruction:lldb.SBInstruction = self.current_instruction\n        mnemonic = None\n        if instruction :\n            mnemonic:str = instruction.GetMnemonic(self.target)\n        else:\n            log_d('warning : instruction is None')\n            log_c('warning : instruction is None')\n\n        cur_frame:lldb.SBFrame = self.thread.GetFrameAtIndex(0)\n        cur_symbol:lldb.SBSymbol = cur_frame.GetSymbol()  \n        flag,value = self.check_ins_call(mnemonic,cur_symbol) # call 指令 操作\n        if flag:\n            log_d('check_ins_call')\n            return value\n            \n        flag,value = self.check_ins_jmp(mnemonic,cur_symbol) # jmp 指令 操作\n        if flag:\n            log_d('check_ins_jmp')\n            return value\n\n        flag,value = self.check_ins_syscall(mnemonic,cur_symbol)  # syscall 指令 操作\n        if flag :\n            log_d('check_ins_syscall')\n            return value\n\n        self.check_ins_other(cur_symbol)  # 其他指令的操作\n        log_d('####### return : check_ins_other. value : CONST_DEAL_WITH_wait_breakpoint')\n        return CONST_DEAL_WITH_wait_breakpoint\n        \n    \n\n       \n\n\nclass WTFunction():\n    def __init__(self, *args):\n        pass\n    def deal_with_fun(self):\n        pass\n        \n\nclass TraceOptionParser(optparse.OptionParser):\n    def __init__(self, result):\n        optparse.OptionParser.__init__(self)\n        self.result = result\n        self.exited = False\n\n    def get_prog_name(self):\n        return \"trace\"\n\n    def exit(self, status=0, msg=None):\n        if msg is not None:\n            # print >>self.result, msg\n            print(msg,file=self.result)\n        self.exited = True\n\ndef parse_options(command, result):\n    global options\n    command_tokens = shlex.split(command)\n    parser = TraceOptionParser(result)\n    parser.add_option(\"-e\",\"--end-address\",action=\"store\",metavar=\"END_ADDRESS\",dest=\"end_address\",help=\"End addresses of trace,using to stop trace thread.More address,use ';' to split.\")\n    parser.add_option(\"-o\",\"--only-tracing-self-module\",action=\"store_true\",dest=\"only_tracing_self_module\",default=True,help=\"Only tracing in current module.Default is True\")\n    parser.add_option(\"-m\",\"--mode-type\",action=\"store\",metavar=\"<instruction/function>\",dest=\"mode_type\",default=\"instruction\",help='Tracing mode,contains function and instruction.Default is instruction mode.')\n    parser.add_option(\"-l\",\"--log-type\",action=\"store\",metavar=\"<trace/debug>\",dest=\"log_type\",default='trace',help=\"Set log type for this tracing. With trace type redirect trace output file. With debug type redirect trace and debug output files.Default is trace type.\")\n    parser.add_option(\"-P\",\"--parser-msgsend-parameters\",action=\"store_true\",dest=\"parser_msgsend_parameters\",default=False,help=\"Parser objc_msgsend function's parameters.Default is False\")\n    parser.add_option(\"-p\",\"--print-tracing-progress\",action=\"store_true\",dest=\"print_tracing_progress\",default=True,help=\"Print tracing progress in console.Default is True\")\n    parser.add_option(\"-s\",\"--suspend-threads-except-current-thread\",action=\"store_true\",dest=\"suspend_threads\",default=True,help=\"Suspend threads except current thread,to clean env.Default is True\")\n    (options, _) = parser.parse_args(command_tokens)\n\n    return parser.exited\n\ndef check_parser_command():\n    global options\n    global t_only_self_module,t_parser_msgsend_parameters\n    global t_log_file,t_log_file_name,d_log_file,d_log_file_name\n\n    if options.end_address is None :\n        print('err : plz input an address where you want to end tracing.')\n        return False\n\n    log_type_arr = ['trace','debug']\n    if not options.log_type in log_type_arr :\n        print('err : plz input -l --log-type value, use \"trace\" or \"debug\".')\n        return False\n\n    mode_type_arr = ['function','instruction']\n    if not options.mode_type in mode_type_arr:\n        print('err : plz input -m --mode-type value, use \"function\" or \"instruction\".')\n        return False\n\n    if options.log_type == 'trace':\n        print(type(t_log_file_name))\n        print(t_log_file_name)\n        t_log_file = open(t_log_file_name,'w')\n\n    if options.log_type == 'debug':\n        t_log_file = open(t_log_file_name,'w')\n        d_log_file = open(d_log_file_name,'w')\n\n    t_only_self_module = options.only_tracing_self_module\n    t_parser_msgsend_parameters = options.parser_msgsend_parameters\n    return True\n\ndef ini_log_file(mode_name:str):\n    import time\n    global log_default_path,t_log_file_name,d_log_file_name\n    timeName = int(time.time())\n    if mode_name == 'instruction':\n        if log_default_path.endswith('/'):\n            t_log_file_name = \"{}{}{}\".format(log_default_path,timeName,'instrace.log')\n            d_log_file_name = \"{}{}{}\".format(log_default_path,timeName,'insdebug.log')\n            log_c('trace log file : {}'.format(t_log_file_name))\n            log_c('debug log file : {}'.format(d_log_file_name))\n        else:\n            t_log_file_name = \"{}/{}{}\".format(log_default_path,timeName,'instrace.log')\n            d_log_file_name = \"{}/{}{}\".format(log_default_path,timeName,'insdebug.log')\n            log_c('trace log file : {}'.format(t_log_file_name))\n            log_c('debug log file : {}'.format(d_log_file_name))\n        \n    elif mode_name == 'function':\n\n        if log_default_path.endswith('/'):\n            t_log_file_name = \"{}{}{}\".format(log_default_path,timeName,'funtrace.log')\n            d_log_file_name = \"{}{}{}\".format(log_default_path,timeName,'fundebug.log')\n            log_c('trace log file : {}'.format(t_log_file_name))\n            log_c('debug log file : {}'.format(d_log_file_name))\n        else:\n            t_log_file_name = \"{}/{}{}\".format(log_default_path,timeName,'funtrace.log')\n            d_log_file_name = \"{}/{}{}\".format(log_default_path,timeName,'fundebug.log')\n            log_c('trace log file : {}'.format(t_log_file_name))\n            log_c('debug log file : {}'.format(d_log_file_name))\n    else:\n        print('err : trace mode err.')    \n\n\ndef test(debugger:lldb.SBDebugger):\n    return False\n    # import sys\n    # import os\n    # print(sys.argv[0])\n    # print(__file__)\n    # current_path = os.path.abspath(__file__)\n    # print(current_path)\n    # father_path = os.path.abspath(os.path.dirname(current_path) + os.path.sep + \".\")\n    # print(father_path)\n    # global options\n    # endAddress = options.end_address\n    # a = re.split(';',endAddress)\n    # for item in a:\n    #     print(type(int(item,16)))\n    #     print(int(item,16))\n    #     print(item)\n    # print(a)\n    # target: lldb.SBTarget = debugger.GetSelectedTarget()\n    # process: lldb.SBProcess = target.GetProcess()\n    # thread: lldb.SBThread = process.GetSelectedThread()\n    # frame: lldb.SBFrame = thread.GetSelectedFrame()\n    # symbol :lldb.SBSymbol = frame.GetSymbol()\n    \n    # print(frame.GetModule())\n    # print('frame : {}'.format(frame))\n    # print('symbol.Instructions : ')\n    # print(symbol.GetInstructions(target))\n    # print('symbol : {}'.format(symbol))\n    # print('symbol.Name : \"{}\"'.format(symbol.GetName()))\n    # print('thread : {}'.format(thread))\n    # print('thread name : {}'.format(thread.GetName()))\n    # ins:lldb.SBInstruction = None\n    # stream:lldb.SBStream = lldb.SBStream()\n    # for ins in symbol.GetInstructions(target):\n    #     # print(ins.GetData(target))\n    #     ins.GetDescription(stream)\n    #     addr :lldb.SBAddress = ins.GetAddress()\n    #     module : lldb.SBModule = addr.GetModule()\n    #     print('module : {}'.format(module))\n    #     sym : lldb.SBSymbol = None\n    #     for sym in module:\n    #         print('sym name : {}'.format(sym.GetName()))\n\n    #     break\n    # print('symbol valid : {}'.format(symbol.IsValid()))\n    # print('symbol DisplayName : {}'.format(symbol.GetDisplayName()))\n    # print('symbol MangledName : {}'.format(symbol.GetMangledName()))\n\n\n    return True\n\ndef trace(debugger: lldb.SBDebugger, command: str, result: lldb.SBCommandReturnObject, internal_dict):\n    '''\n    Traces execution of the symbol in the currently selected frame.\n    trace -h/--help, for full help\n    '''\n    global options\n    if parse_options(command, result):\n        return\n    \n    ####################################################\n    ########################测 试########################\n    ####################################################\n    if test(debugger):\n            return\n    ####################################################\n\n    ini_log_file(options.mode_type)\n\n    if not check_parser_command():\n        return\n    \n\n    wait_event = threading.Event()\n    wait_event.clear()\n    notify_event = threading.Event()\n    notify_event.clear()\n    \n    target: lldb.SBTarget = debugger.GetSelectedTarget()\n    broadcaster: lldb.SBBroadcaster = target.GetBroadcaster()\n    log_d(\"Target: {}\".format(str(target)))\n    process: lldb.SBProcess = target.GetProcess()\n    log_d(\"Process: {}\".format(str(process)))\n    log_d(\"Broadcaster: {}\".format(str(broadcaster)))\n    if options.suspend_threads :\n        suspend_threads_escape_select_thread(process,True)\n\n    listener = lldb.SBListener(\"trace breakpoint listener\")\n    rc = broadcaster.AddListener(listener, lldb.SBProcess.eBroadcastBitStateChanged)\n    my_thread = WTListeningThread(wait_event, notify_event,listener, process)\n    my_thread.start()\n\n    thread: lldb.SBThread = process.GetSelectedThread()\n    log_d(\"Thread: {}\".format(str(thread)))\n    \n    frame: lldb.SBFrame = thread.GetSelectedFrame()\n    \n    module: lldb.SBModule = frame.GetModule()\n    if frame.GetFrameID() == 0xFFFFFFFF:\n        log_d(\"Invalid frame, has your process started?\")\n        return\n\n    insObj = WTInstruction(target,thread,frame,debugger,TRACE_TYPE_Instrument,endAddress=options.end_address)\n    ## 初始化 环境 \n    insObj.init_env()\n    global num_for_print_progress\n    insCount = 0\n    test_index = 0\n    while True:\n        log_d('index : {}'.format(test_index))\n        # 打印进度\n        if options.print_tracing_progress :\n            if insCount % num_for_print_progress == 0 and insCount > 0:\n                insObj.print_tracing_progress(insCount)\n            insCount = insCount + 1\n\n        # 更新当前 instruction / instructionList\n        log_d(\"////////////////////////////////loop begin////////////////////////////////\")\n        insObj.updata_instruction_instructionList() # 更新所有的 指令 ，更新当前 指令 \n\n        # ins : 设置断点，进行有必要的 单步 调试\n        # fun : 设置断点\n        ret = insObj.deal_with() # 处理 指令\n\n        # 保存指令\n        insObj.updata_last_instruction()\n\n        log_d(\"=================== Stopped at: ====================\")\n        log_d(\"Frame: {}, symbol: {}, pc: {pc:#x}\".format(str(frame), str(frame.GetSymbol()), pc=frame.GetPC()))\n        # 判断结果\n        if ret == CONST_DEAL_WITH_error:\n            log_c('err : deal with error.')\n            log_d('err : deal with error.')\n            insObj.clean_env()\n            break\n\n        if ret == CONST_DEAL_WITH_continue:\n            continue\n\n        if ret == CONST_DEAL_WITH_break :\n            break\n        continue_and_wait_for_breakpoint(process,thread,my_thread,wait_event,notify_event)\n\n\n\n    if options.suspend_threads :\n        suspend_threads_escape_select_thread(process,False)\n    my_thread.exit()\n    wait_event.set()\n    my_thread.join()\n    broadcaster.RemoveListener(listener)\n    log_d('Listener thread exited completing')\n    log_flush()\n\n\n############################################################################################################################################################\n#######################################################################traceblock###########################################################################\n############################################################################################################################################################\n\nclass WTBlock():\n    def __init__(self, target, thread, frame,debugger,endAddress=None):\n        self.target:lldb.SBTarget = target\n        self.thread:lldb.SBThread = thread\n        self.frame:lldb.SBFrame = frame\n        self.debugger:lldb.SBDebugger = debugger\n\n        self.current_instruction_list = {}\n        self.end_trace_address = []\n        self.block_list = {} # 存贮所有的 block\n\n        # \n        # {\n        #     addr : {  # 这里是断点地址\n        #         'index' : 0 # 这里是断点信息\n        #         'breakpoint' : None # 这里是 lldb.SBBreakpoint\n        #     }\n        # }\n        self.breakpoint_list = {} # 断点列表\n        \n        self.loop_flag = False\n        self.append_msg = ''  \n\n        # log\n        self.last_block_msg = '' \n        self.last_isnts_msg = ''\n        self.last_reg_msg = ''\n\n        ## \n        self.test_test_index = 0\n\n        for item in re.split(';',endAddress):\n            self.end_trace_address.append(int(item,16)) # 结束 Trace 地址\n\n    def initEnv(self):\n        cur_pc = self.get_current_pc()\n        self.block_add_block_to_block_list(cur_pc)\n        for item in self.end_trace_address :\n            self.block_add_breakpoint(item)  # 给结束地址下断点\n\n    def block_set_loop_flag(self,flag_value):\n        self.loop_flag = flag_value\n\n    def block_add_append_msg(self,msg):\n        self.append_msg = '{}[{}]'.format(self.append_msg,msg)            \n        \n\n    def block_clear_append_msg(self):\n        self.append_msg = ''\n\n    def block_delete_breakpoint(self,inst_addr):\n        if inst_addr in self.breakpoint_list :\n            index_value = self.breakpoint_list[inst_addr]['index']\n            delete_breakpoint:lldb.SBBreakpoint = self.breakpoint_list[inst_addr]['breakpoint']\n            if index_value > 1 :\n                self.breakpoint_list[inst_addr]['index'] = index_value -1\n            elif index_value == 1:\n                log_d('delete breakpoint at : {}'.format(hex(inst_addr)))\n                self.target.BreakpointDelete(delete_breakpoint.GetID())\n                self.breakpoint_list[inst_addr]['index'] = 0\n                self.breakpoint_list.pop(inst_addr)\n            else:\n                log_d('err : delete breakpoint with wrong index . < index : {} >'.format(index_value))\n\n    def block_add_breakpoint(self,inst_addr):\n        if inst_addr in self.breakpoint_list:\n            # index_value = self.breakpoint_list[inst_addr]['index']\n            # if index_value > 0 :\n            #     print('increase breakpoint index at : {}'.format(hex(inst_addr)))\n            #     self.breakpoint_list[inst_addr]['index'] = index_value + 1\n            # else:\n            #     print('err : add breakpoint with wrong index. < index : {} >'.format(index_value))\n            log_d('breakpoint at {} had been exist.'.format(hex(inst_addr)))\n        else:\n            item = {}\n            breakpoint :lldb.SBBreakpoint = self.target.BreakpointCreateByAddress(inst_addr)\n            breakpoint.SetThreadID(self.thread.GetThreadID())\n            item['index'] = 1\n            item['breakpoint'] = breakpoint\n            self.breakpoint_list[inst_addr] = item\n            log_d('add breakpoint at : {}'.format(hex(inst_addr)))\n    def block_add_block_to_block_list(self,block_id):\n        if  not (block_id in self.block_list) :\n            log_d('>>>>>> add block : {}  >>> value : None.'.format(hex(block_id)))\n            self.block_list[block_id] = None\n\n    # 获得当前 pc\n    def get_current_pc(self):\n        now_frame :lldb.SBFrame = self.thread.GetSelectedFrame()\n        if now_frame:\n            return now_frame.GetPC()\n        return None\n    # \n    def block_update_current_ins(self):\n        frame : lldb.SBFrame = self.thread.GetSelectedFrame()\n        # symbol:lldb.SBSymbol = frame.GetSymbol()\n        # # 给 current_instruction_list 赋值\n        # # 获得 当前 symbol 下的 instructionlist\n        # insts : lldb.SBInstructionList = symbol.GetInstructions(self.target)\n\n        cur_pc = self.get_current_pc()\n        \n        if not (cur_pc in self.current_instruction_list)  :\n            # 清空一哈\n            self.current_instruction_list = {}\n            # 更新 self.current_instruction_list\n\n            target: lldb.SBTarget = self.debugger.GetSelectedTarget()\n            process: lldb.SBProcess = target.GetProcess()\n            thread: lldb.SBThread = process.GetSelectedThread()\n            frame: lldb.SBFrame = thread.GetSelectedFrame()\n            symbol :lldb.SBSymbol = frame.GetSymbol()\n            insts :lldb.SBInstructionList = symbol.GetInstructions(target)\n            # func : lldb.SBFunction = frame.GetFunction()\n            # insts : lldb.SBInstructionList = func.GetInstructions(self.target)     \n            for inst in insts :\n                instAddr :lldb.SBAddress = inst.GetAddress()\n                addr = instAddr.GetLoadAddress(self.target)\n                if not (addr in self.current_instruction_list) :\n                    self.current_instruction_list[addr] = inst\n        \n        return cur_pc\n\n\n    # 判断当前 ins 是否在 trace 的结束列表中\n    def block_check_current_ins_in_end_tracing_address_list(self,curIns):\n        if curIns in self.end_trace_address :\n            return True\n        return False\n    \n    def block_update_block_data(self,block_id,block_dic):\n        if block_id in self.block_list:\n            block_data = self.block_list[block_id]\n            if not block_data :\n                self.block_list[block_id] = block_dic\n            else :\n                log_d('>> block : {} had been update'.format(hex(block_id)))\n        else:\n            log_d('err : block id dont input to block list.')\n\n    def block_update_current_block(self):        \n        # 需要在 bl 以及 jmp 目标地址，和条件jmp的下一条指令处下断点，以及 增加对应的 block 到 blockList 中\n        cur_pc = self.get_current_pc()\n        # print(self.current_instruction_list)\n        inst :lldb.SBInstruction = self.current_instruction_list[cur_pc]\n\n        if (cur_pc in self.block_list) and ( self.block_list[cur_pc]) :  \n            self.block_set_loop_flag(True)\n            self.block_delete_breakpoint(cur_pc)\n            return self.block_list[cur_pc]\n\n        use_inst = inst\n        block_ins_list = {}\n        need_break = False\n        log_d('update block : {} insts :'.format(hex(cur_pc)))\n        while True :\n            mnemonic: str = use_inst.GetMnemonic(self.target)\n            inst_addr = use_inst.GetAddress().GetLoadAddress(self.target)\n            next_addr = inst_addr + use_inst.GetByteSize()\n            operands = use_inst.GetOperands(self.target)\n\n            flag = False\n            for item in CONST_DEVICE_info_list[DEVICE][CONST_INS_call] :\n                if mnemonic.startswith(item) :\n                    flag = True\n                    break\n            \n            if flag :\n                self.block_add_breakpoint(inst_addr)\n                block_ins_list[inst_addr] = use_inst # 代码加入到 block_ins_list \n                if next_addr in self.current_instruction_list :\n                    use_inst = self.current_instruction_list[next_addr] # 更新 use_inst\n                else :\n                    break\n                continue\n\n            flag = False\n            for item in CONST_DEVICE_info_list[DEVICE][CONST_INS_jmp]:\n                if item == mnemonic :\n                    flag = True\n                    need_break = True\n                    break\n            \n            if flag :  \n                self.block_add_block_to_block_list(int(operands,16))    # 添加block 到 block_list 中 \n                self.block_add_breakpoint(int(operands,16))# 在 int(operands,16) 处下断点\n\n            if not need_break :        \n                flag = False\n                for item in CONST_DEVICE_info_list[DEVICE][CONST_INS_condition_jmp] :\n                    if  mnemonic.startswith(item):\n                        flag = True\n                        need_break = True\n                        break\n                if flag :\n                    if int(operands,16) > inst_addr :    \n                        self.block_add_block_to_block_list(int(operands,16)) \n                        self.block_add_breakpoint(int(operands,16)) # 在 operands 下断点\n\n                    self.block_add_block_to_block_list(next_addr)\n                    self.block_add_breakpoint(next_addr) # 在 next_addr 下断点\n\n            \n            block_ins_list[inst_addr] = use_inst # 代码加入到 block_ins_list \n            if need_break :\n                break\n\n            if next_addr in self.current_instruction_list :\n                use_inst = self.current_instruction_list[next_addr] # 更新 use_inst\n            else :\n                break\n        # self.block_list[cur_pc] = block_ins_list\n        # print('block : {} \\n{}:'.format(hex(cur_pc),self.block_list[cur_pc]))\n        return block_ins_list\n\n\n    def block_at_bl(self,curIns):\n        ins:lldb.SBInstruction = self.current_instruction_list[curIns]\n        mnem:str = ins.GetMnemonic(self.target)\n        for item in CONST_DEVICE_info_list[DEVICE][CONST_INS_call]:\n            if mnem.startswith(item) :\n                return True\n        return False\n\n    def block_at_header(self,curIns):\n        if curIns in self.block_list :\n            return True\n        return False\n\n    ##############################\n    def block_step_into(self):\n        self.thread.StepInstruction(False)\n\n    def block_get_data_about_function_and_symbol(self,curIns):\n        target: lldb.SBTarget = self.debugger.GetSelectedTarget()\n        process: lldb.SBProcess = target.GetProcess()\n        thread: lldb.SBThread = process.GetSelectedThread()\n        frame: lldb.SBFrame = thread.GetSelectedFrame()\n        symbol :lldb.SBSymbol = frame.GetSymbol()\n        func : lldb.SBFunction = frame.GetFunction()\n        # insts:lldb.SBInstructionList = func.GetInstructions(target)\n        # inst:lldb.SBInstruction = None\n        # block_delete_breakpoint\n        self.block_delete_breakpoint(curIns)\n\n        if func.IsValid():\n            return True,symbol.GetName()\n\n        return False,symbol.GetName()\n\n\n    def block_get_reg_msg(self):\n        reg_msg = ''\n        target: lldb.SBTarget = self.debugger.GetSelectedTarget()\n        process: lldb.SBProcess = target.GetProcess()\n        thread: lldb.SBThread = process.GetSelectedThread()\n        frame: lldb.SBFrame = thread.GetSelectedFrame()\n\n        registerSet :lldb.SBValueList = frame.GetRegisters()\n        regs:lldb.SBValue = registerSet.GetValueAtIndex(0)\n        for reg in regs :     \n            if reg_msg == \"\" :\n                reg_msg = '{}:{}'.format(reg.name,reg.value)\n            else:\n                reg_msg = '{}|{}:{}'.format(reg_msg,reg.name,reg.value)\n\n            if reg.name == 'pc' :\n                break\n\n        return reg_msg\n\n    def block_get_current_insts_msg(self,block_id):\n        global ASLR\n        target: lldb.SBTarget = self.debugger.GetSelectedTarget()\n        isnts_msg = ''\n        if  not self.loop_flag :\n            # isnts_msg = '0x12345 mov x0,1'\n            if block_id in self.block_list:\n                cur_block = self.block_list[block_id]\n                inst:lldb.SBInstruction = None\n                if cur_block :\n                    for key,inst in cur_block.items():\n                        inst_msg = '{: <5} {}'.format(inst.GetMnemonic(target),inst.GetOperands(target))\n                        if isnts_msg == \"\" :\n                            isnts_msg = '{: <10}  {}'.format(hex(key - ASLR),inst_msg)\n                        else:\n                            isnts_msg = '{}\\n\\t{: <10}  {}'.format(isnts_msg,hex(key - ASLR),inst_msg)\n\n        return isnts_msg\n\n    ################################\n    # log 输出 格式\n    # block_id :\n\t# {\n\t#     addr : inst\n\t# \t...\n\t# }<函数名|函数名|..>[x0:value|x1:value|....]\n    # block_id :\n\t#     {}<函数名|函数名|..>[x0:value|x1:value|....]\n    #\n    # out_msg = \"%s\\n{\\n\\t%s\\n}<%s>[%s]\" % ('block id : 0x1233333','0x12345 mov x0,1','malloc|strlen','x0:0x1234|x1:0x222222')\n    def block_log_msg(self,block_id):\n        global ASLR\n        self.test_test_index = self.test_test_index + 1\n        \n        block_msg = \"{} =>> block id : {}\".format(self.test_test_index,hex(block_id-ASLR))\n        isnts_msg = self.block_get_current_insts_msg(block_id)   \n        reg_msg = self.block_get_reg_msg()\n\n        if not (self.last_block_msg == '' and self.last_isnts_msg == '' and self.last_reg_msg == '') :\n            out_msg = \"%s\\n{\\n\\t%s\\n}<%s>[%s]\" % (self.last_block_msg,self.last_isnts_msg,self.append_msg,self.last_reg_msg)\n            log_t(out_msg)\n\n        self.last_block_msg = block_msg\n        self.last_isnts_msg = isnts_msg\n        self.last_reg_msg = reg_msg\n\n        # 清空 append_msg\n        self.append_msg = ''\n\n    def block_log_end_msg(self):\n        if not (self.last_block_msg == '' and self.last_isnts_msg == '' and self.last_reg_msg == '') :\n            out_msg = \"%s\\n{\\n\\t%s\\n}<%s>[%s]\" % (self.last_block_msg,self.last_isnts_msg,self.append_msg,self.last_reg_msg)\n            log_t(out_msg)\n\n        self.last_block_msg = ''\n        self.last_isnts_msg = ''\n        self.last_reg_msg = ''\n        \n        self.append_msg = ''\n        \n\n    def block_get_symbol_name(self):\n        target: lldb.SBTarget = self.debugger.GetSelectedTarget()\n        process: lldb.SBProcess = target.GetProcess()\n        thread: lldb.SBThread = process.GetSelectedThread()\n        frame: lldb.SBFrame = thread.GetSelectedFrame()\n        symbol :lldb.SBSymbol = frame.GetSymbol()\n        return symbol.GetName()\n\n\n    def block_print_tracing_progress(self,count):\n        # 当前trace的总行数 内存地址:文件地址: <函数名>\n        global ASLR\n        file_addr = 0\n        cur_pc = self.get_current_pc()\n        if  cur_pc == 0 :\n            log_c('{: <10}  err .'.format(count))\n        else:\n            file_addr = cur_pc - ASLR\n            if cur_pc in self.current_instruction_list:   \n                out_str = '{: <10}  {} : {} <{}>'.format(count,hex(cur_pc),hex(file_addr),self.block_get_symbol_name())\n                log_c(out_str)\n            else:\n                out_str = '{: <10} {}'.format(count,hex(cur_pc))\n                log_c(out_str)\n\n    def block_get_block_id(self,block):\n        retaddr = 0\n        for addr in block.keys():\n            if retaddr == 0 :\n                retaddr = addr\n            else:\n                if retaddr > addr :\n                    retaddr = addr\n        \n        return retaddr\n\n\n    def block_print(self):\n        print('---> block_list <---')\n        for item in self.block_list:\n            print(hex(item))\n\n        print('---> breakpoint_list <---')\n        for item in self.breakpoint_list :\n            print(hex(item))\n\n        print('--------------------------')\n\n\n\n\ndef block_parser_options(command, result):\n    global options\n    command_tokens = shlex.split(command)\n    parser = TraceOptionParser(result)\n    parser.add_option(\"-e\",\"--end-address\",action=\"store\",metavar=\"END_ADDRESS\",dest=\"end_address\",help=\"End addresses of trace,using to stop trace thread.More address,use ';' to split.\")\n    parser.add_option(\"-l\",\"--log-type\",action=\"store\",metavar=\"<trace/debug>\",dest=\"log_type\",default='trace',help=\"Set log type for this tracing. With trace type redirect trace output file. With debug type redirect trace and debug output files.Default is trace type.\")\n    parser.add_option(\"-p\",\"--print-tracing-progress\",action=\"store_true\",dest=\"print_tracing_progress\",default=True,help=\"Print tracing progress in console.Default is True\")\n    parser.add_option(\"-s\",\"--suspend-threads-except-current-thread\",action=\"store_true\",dest=\"suspend_threads\",default=True,help=\"Suspend threads except current thread,to clean env.Default is True\")\n    \n    (options, _) = parser.parse_args(command_tokens)\n\n    return parser.exited\n\n\ndef block_ini_log_file():\n    import time\n    global log_default_path,t_log_file_name,d_log_file_name\n    timeName = int(time.time())\n\n    if log_default_path.endswith('/'):\n        t_log_file_name = \"{}{}{}\".format(log_default_path,timeName,'blocktrace.log')\n        d_log_file_name = \"{}{}{}\".format(log_default_path,timeName,'blockdebug.log')\n        log_c('trace log file : {}'.format(t_log_file_name))\n        log_c('debug log file : {}'.format(d_log_file_name))\n    else:\n        t_log_file_name = \"{}/{}{}\".format(log_default_path,timeName,'blocktrace.log')\n        d_log_file_name = \"{}/{}{}\".format(log_default_path,timeName,'blockdebug.log')\n        log_c('trace log file : {}'.format(t_log_file_name))\n        log_c('debug log file : {}'.format(d_log_file_name))\n \n\n\ndef block_check_parser_command():\n    global options\n    global t_log_file,t_log_file_name,d_log_file,d_log_file_name\n\n    if options.end_address is None :\n        print('err : plz input an address where you want to end tracing.')\n        return False\n\n    log_type_arr = ['trace','debug']\n    if not options.log_type in log_type_arr :\n        print('err : plz input -l --log-type value, use \"trace\" or \"debug\".')\n        return False\n\n    if options.log_type == 'trace':\n        print(type(t_log_file_name))\n        print(t_log_file_name)\n        t_log_file = open(t_log_file_name,'w')\n\n    if options.log_type == 'debug':\n        t_log_file = open(t_log_file_name,'w')\n        d_log_file = open(d_log_file_name,'w')\n\n    return True\n\n\ndef test_block(debugger:lldb.SBDebugger):\n    \n    return False\n\n    target: lldb.SBTarget = debugger.GetSelectedTarget()\n    process: lldb.SBProcess = target.GetProcess()\n    thread: lldb.SBThread = process.GetSelectedThread()\n    frame: lldb.SBFrame = thread.GetSelectedFrame()\n    symbol :lldb.SBSymbol = frame.GetSymbol()\n    func : lldb.SBFunction = frame.GetFunction()\n\n    # out_msg = \"%s\\n{\\n\\t%s\\n}<%s>[%s]\" % ('block id : 0x1233333','0x12345 mov x0,1','malloc|strlen','x0:0x1234|x1:0x222222')\n\n    # print(out_msg)\n    # registerSet :lldb.SBValueList = frame.GetRegisters()\n    # regs:lldb.SBValue = registerSet.GetValueAtIndex(0)\n    # print('num is : {}'.format(regs.GetNumChildren()))\n    # for reg in regs :     \n    #     print('{} : {}'.format(reg.name,reg.value))\n    #     if reg.name == 'pc' :\n    #         break\n    # print(symbol.GetInstructions(target))\n\n    # # symbol 可执行文件里有，链接库里有\n    # # func 可执行文件里有，但是 链接库里 没有\n    # if func.IsValid() :\n    #     # insts:lldb.SBInstructionList = func.GetInstructions(target)\n    #     # inst:lldb.SBInstruction = None\n    #     # print('isnts : ')\n    #     # print(insts)\n    #     print('func : {}'.format(func))\n    #     print('func name : {}'.format(func.GetName()))  \n    # # print('symbol : {}'.format(symbol))\n    # # print('symbol DisplayName : {}'.format(symbol.GetDisplayName()))\n    # # print('symbol MangledName : {}'.format(symbol.GetMangledName()))\n    # print('symbol name : {}'.format(symbol.GetName()))\n\n\n    # for inst in insts :  \n    #     print('|{}|-----|{}|'.format(inst.GetMnemonic(target),inst.GetOperands(target)))\n    #     pass\n    cur_block_ins_list = None # 直接更新\n    blockObj = WTBlock(target,thread,frame,debugger)\n    blockObj.initEnv()\n    cur_ins = blockObj.block_update_current_ins()\n    print('cur ins : {}'.format(hex(cur_ins)))\n    if not cur_block_ins_list :\n        cur_block_ins_list = blockObj.block_update_current_block()\n\n    # if not (cur_ins in cur_block_ins_list) :\n    #     cur_block_ins_list = blockObj.block_update_current_block()\n\n    print('--> block_ins_list <---')\n    item : lldb.SBInstruction = None  \n    for _,item in cur_block_ins_list.items() :\n        print('{}      {}  {}'.format(hex(item.GetAddress().GetLoadAddress(target)),item.GetMnemonic(target),item.GetOperands(target)))\n\n\n    blockObj.block_print()\n\ndef trace_block(debugger: lldb.SBDebugger, command: str, result: lldb.SBCommandReturnObject, internal_dict):\n    global options\n    if block_parser_options(command, result):\n        return\n    \n    ####################################################\n    ########################测 试########################\n    ####################################################\n    if test_block(debugger):\n            return\n    ####################################################\n\n    block_ini_log_file()\n\n\n    if not block_check_parser_command():\n        return\n    \n    wait_event = threading.Event()\n    wait_event.clear()\n    notify_event = threading.Event()\n    notify_event.clear()\n    \n    target: lldb.SBTarget = debugger.GetSelectedTarget()\n    broadcaster: lldb.SBBroadcaster = target.GetBroadcaster()\n    print(\"Target: {}\".format(str(target)))\n    process: lldb.SBProcess = target.GetProcess()\n    print(\"Process: {}\".format(str(process)))\n    print(\"Broadcaster: {}\".format(str(broadcaster)))\n    if options.suspend_threads :\n        suspend_threads_escape_select_thread(process,True)\n\n    listener = lldb.SBListener(\"trace breakpoint listener\")\n    rc = broadcaster.AddListener(listener, lldb.SBProcess.eBroadcastBitStateChanged)\n    my_thread = WTListeningThread(wait_event, notify_event,listener, process)\n    my_thread.start()\n\n    thread: lldb.SBThread = process.GetSelectedThread()\n    print(\"Thread: {}\".format(str(thread)))\n    \n    frame: lldb.SBFrame = thread.GetSelectedFrame()\n    \n    module: lldb.SBModule = frame.GetModule()\n    if frame.GetFrameID() == 0xFFFFFFFF:\n        print(\"Invalid frame, has your process started?\")\n        return\n    \n    blockObj = WTBlock(target,thread,frame,debugger,endAddress=options.end_address)\n    blockObj.initEnv()\n    \n    cur_block = None # 直接更新\n    blockCount = 0\n    while True :\n        # 打印进度\n        if options.print_tracing_progress :\n            if blockCount % num_for_print_progress == 0 and blockCount > 0:\n                blockObj.block_print_tracing_progress(blockCount)\n            blockCount = blockCount + 1\n        log_d(\"=================== Stopped at: ====================\")\n        log_d(\"Frame: {}, symbol: {}, pc: {pc:#x}\".format(str(frame), str(frame.GetSymbol()), pc=frame.GetPC()))\n        cur_ins = blockObj.block_update_current_ins()\n\n        if blockObj.block_check_current_ins_in_end_tracing_address_list(cur_ins):\n            print('end tracing....... at : {}'.format(hex(cur_ins)))\n            blockObj.block_log_end_msg()\n            log_d('end tracing....... at : {}'.format(hex(cur_ins)))\n            # blockObj.block_print()\n            break\n        \n        if (not cur_block ) or not (cur_ins in cur_block): \n            cur_block = blockObj.block_update_current_block() # 需要在 bl 以及 jmp 目标地址，和条件jmp的下一条指令处下断点，以及 增加对应的 block 到 blockList 中\n            blockObj.block_update_block_data(cur_ins,cur_block)\n\n\n        at_bl_flag = blockObj.block_at_bl(cur_ins)\n        at_header_flag = blockObj.block_at_header(cur_ins)\n\n        if at_bl_flag and at_header_flag :\n            # 当前指令 是 bl 而且是 block 头\n            # 输出 信息\n            blockObj.block_log_msg(cur_ins)\n            blockObj.block_set_loop_flag(False)\n            # 单步进入，然后获得 symble name 和 function name\n            blockObj.block_step_into()\n            _,symbol_name = blockObj.block_get_data_about_function_and_symbol(cur_ins) \n            blockObj.block_add_append_msg('') # blockObj.block_add_append_msg(msg) # 把信息 加入 到 \n\n        elif at_bl_flag and (not at_header_flag):\n            # 当前指令 仅仅是 bl\n            # 单步进入，然后获得 symble name 和 function name\n            blockObj.block_step_into()\n            _,symbol_name = blockObj.block_get_data_about_function_and_symbol(cur_ins)\n            blockObj.block_add_append_msg(symbol_name) # blockObj.block_add_append_msg(msg) # 把信息 加入 到 \n            \n        elif at_header_flag and (not at_bl_flag):\n            # 当前指令 仅仅是 block 头,在进来的时候，已经搞定\n            # 输出 信息\n            blockObj.block_log_msg(cur_ins)\n            blockObj.block_set_loop_flag(False)\n        else:\n            log_d('err : ins out of control.')\n            print('err : ins out of control.')\n            break\n        \n        # 10分钟 刷新一次缓存，把缓存 写入到 block list 文件中  xxxxx_block_list.txt\n        # 清空 blockObj.block_list\n\n        continue_and_wait_for_breakpoint(process,thread,my_thread,wait_event,notify_event)      \n\n    if options.suspend_threads :\n        suspend_threads_escape_select_thread(process,False)\n    my_thread.exit()\n    wait_event.set()\n    my_thread.join()\n    broadcaster.RemoveListener(listener)\n    print('Listener thread exited completing')\n    log_flush()\n\n\n\ndef init_ASLR(debugger:lldb.SBDebugger):   \n    global ASLR\n    interpreter:lldb.SBCommandInterpreter = debugger.GetCommandInterpreter()\n    returnObject = lldb.SBCommandReturnObject()\n    interpreter.HandleCommand('image list -o', returnObject)\n    output = returnObject.GetOutput()\n    match = re.match(r'.+(0x[0-9a-fA-F]+)', output)\n    if match:\n        ASLRHexStr:str = match.group(1)\n        ASLR = int(ASLRHexStr,16)\n        print('ALSR : {}'.format(ASLRHexStr))\n        return ASLRHexStr\n    else:\n        ASLR = ''\n        print('err : ALSR is None')\n        return None\n\ndef setDefaultPath(debugger: lldb.SBDebugger, command: str, result: lldb.SBCommandReturnObject, internal_dict):\n    global log_default_path\n    log_default_path = command\n    # 还需要判断这个 路径存在否\n    print(command)\n    \ndef defaultPath(debugger: lldb.SBDebugger, command: str, result: lldb.SBCommandReturnObject, internal_dict):\n    global log_default_path\n    print(log_default_path)\n\ndef __lldb_init_module(debugger:lldb.SBDebugger, internal_dict):\n    global log_default_path\n    init_ASLR(debugger)\n    log_default_path = os.path.abspath(os.path.dirname(os.path.abspath(__file__)) + os.path.sep + \".\")\n    debugger.HandleCommand('command script add -f lldbTrace.trace trace')\n    debugger.HandleCommand('command script add -f lldbTrace.setDefaultPath setlogpath')\n    debugger.HandleCommand('command script add -f lldbTrace.defaultPath logpath')\n    print('WT::The \"trace\" python command has been installed and is ready for use.')\n\n\n\n    print('WT::Default path =>>>> {}'.format(log_default_path))\n    print('    use : logpath command to look up logfile default path.')\n    print('    use : setlogpath <PATH> command to reset logfile default path.')\n\n    debugger.HandleCommand('command script add -f lldbTrace.trace_block trace_b')\n    print('WT::The \"trace_b\" python command has been installed and is ready for use.')\n\n\n"
  },
  {
    "path": "main.mm",
    "content": "//\n//  main.m\n//  checkDemo\n//\n//  Created by wt on 2021/4/21.\n//\n\n#import <Foundation/Foundation.h>\n#import <CommonCrypto/CommonCrypto.h>\n#import <CommonCrypto/CommonCryptor.h>\n#import <CoreLocation/CoreLocation.h>\n#include <sys/stat.h>\n#import <objc/runtime.h>\n#import <Foundation/NSObject.h>\n#import \"WTAes.hpp\"\n\nint test(int a,int b,int c){\n    int  tmp = 2 * c;\n    return  a + b + tmp;\n}\n\nint test_fun(){\n    NSString * a = @\"{\\\"b1\\\":\\\"\\\",\\\"b2\\\":1,\\\"b3\\\":\\\"AAAAAAAAAAAAAMnu601KCPF0Mj3cObiE77iT8YWCbhK1vSgWHJ3uNlYTdmODBjMGMyZGMn-JGVHeeVP_WmIdd2TFi6Si0TpSJ8_Q\\\",\\\"b4\\\":\\\"\\\",\\\"b5\\\":1,\\\"b6\\\":{\\\"c1\\\":\\\"com.meituan.imeituan\\\",\\\"c2\\\":\\\"56226DD0E7DEB85C417DD793041E5CC9\\\",\\\"c3\\\":\\\"11.7.202\\\",\\\"c4\\\":117202,\\\"c5\\\":-2}}\";\n    NSLog(@\"%ld\",[a length]);\n    unsigned char arr[] = {\n        0xc2,0x55,0xe9,0x74,0xb0,0xd6,0x39,0xb2,\n        0xf3,0x0e,0x85,0x98,0x6b,0xd0,0xb8,0xc9,\n        0x35,0x50,0x56,0xe0,0xef,0xe7,0x1d,0x2c,\n        0x5a,0x0e,0x76,0x76,0xd8,0x6f,0xda,0xee,\n        0xf5,0xfe,0x78,0x0f,0x08,0x3d,0x47,0xe2,\n        0x51,0xf3,0xc1,0x75,0xf5,0xf1,0x40,0x10,\n        0x74,0xd6,0x62,0x5e,0xe7,0x51,0xce,0xd7,\n        0x8b,0x4d,0x66,0x95,0x34,0x33,0xda,0x3b,\n        0x0f,0xe7,0x55,0x27,0x5b,0xe8,0x11,0x2c,\n        0xcd,0xc5,0xfa,0x76,0x97,0x8c,0x4c,0xcc,\n        0x33,0x1e,0xe5,0xf2,0x5e,0xba,0xca,0xae,\n        0x6c,0x32,0x21,0x18,0x1e,0x5e,0x32,0x69,\n        0x00,0x3c,0xfa,0x14,0xea,0x62,0xed,0x81,\n        0x59,0xad,0x70,0x7b,0x56,0xa7,0x1d,0x40,\n        0x44,0x23,0x69,0x3e,0xda,0x14,0xb8,0x42,\n        0x67,0x9f,0xc7,0x07,0xe4,0x92,0xd3,0xff,\n        0x5b,0x6d,0x0d,0xd6,0x3c,0x0d,0xcb,0x33,\n        0x95,0x4f,0x8c,0xbe,0xd1,0xbf,0x87,0x8e,\n        0x24,0x03,0x8b,0xc4,0xfa,0xfd,0x25,0x7d,\n        0xe9,0x40,0xda,0xe8,0xc0,0xf4,0xd5,0x12,\n        0x6f,0xf0,0x3d,0x3e,0xca,0x96,0x63,0x72,\n        0x9d,0x2c,0x72,0xbb,0xef,0x73,0xac,0xaa,\n        0xfd,0xd1,0x4c,0x2d,0x38,0x9c,0xd2,0x19,\n        0x54,0x43,0x1b,0xd5,0x9d,0xa5,0x15,0x7d,\n        0xf2,0x27,0x7a,0x1d,0xee,0x91,0xfc,0xf2,\n        0xca,0x9b,0xee,0x14,0x5c,0xe5,0x6d,0x5c,\n        0x31,0xe6,0x47,0x45,0xf2,0x68,0xb8,0x32,\n        0x85,0x08,0x68,0x4e,0x57,0x80,0x82,0xc9,\n        0x8f,0xe2,0x7c,0xff,0x79,0xd6,0xc7,0xba,\n        0x68,0xf7,0x9a,0x13,0xbf,0x99,0x01,0xe8,\n        0x98,0x7a,0xd6,0xab,0xb8,0xae,0x0c,0x3f,\n        0xe7,0xb0};\n    \n    NSData * data = [[NSData alloc] initWithBytes:arr length:0xfd];\n    NSData *base64Data = [data base64EncodedDataWithOptions:0];\n    \n    NSString *base64 = [[NSString alloc] initWithData:base64Data encoding:NSUTF8StringEncoding];\n    NSLog(@\"%@\",base64);\n    \n    int value = test(2, 3, 5);\n    NSString * str = [NSString stringWithFormat:@\"%d\",value];\n    [str stringByAppendingString:@\"abc\"];\n    \n//    @\"wlXpdLDWObLzDoWYa9C4yTVQVuDv5x0sWg52dthv2u71/ngPCD1H4lHzwXX18UAQdNZiXudRzteLTWaVNDPaOw/nVSdb6BEszcX6dpeMTMwzHuXyXrrKrmwyIRgeXjJpADz6FOpi7YFZrXB7VqcdQEQjaT7aFLhCZ5/HB+SS0/9bbQ3WPA3LM5VPjL7Rv4eOJAOLxPr9JX3pQNrowPTVEm/wPT7KlmNynSxyu+9zrKr90UwtOJzSGVRDG9WdpRV98id6He6R/PLKm+4UXOVtXDHmR0XyaLgyhQhoTleAgsmP4nz/edbHumj3mhO/mQHomHrWq7iuDD/nsA==\";\n//    @\"wlXpdLDWObLzDoWYa9C4yTVQVuDv5x0sWg52dthv2u71/ngPCD1H4lHzwXX18UAQdNZiXudRzteLTWaVNDPaOw/nVSdb6BEszcX6dpeMTMwzHuXyXrrKrmwyIRgeXjJpADz6FOpi7YFZrXB7VqcdQEQjaT7aFLhCZ5/HB+SS0/9bbQ3WPA3LM5VPjL7Rv4eOJAOLxPr9JX3pQNrowPTVEm/wPT7KlmNynSxyu+9zrKr90UwtOJzSGVRDG9WdpRV98id6He6R/PLKm+4UXOVtXDHmR0XyaLgyhQhoTleAgsmP4nz/edbHumj3mhO/mQHomHrWq7iuDD/nsCgAMA==\";\n    \n//    wlXpdLDWObLzDoWYa9C4yTVQVuDv5x0sWg52dthv2u71/ngPCD1H4lHzwXX18UAQdNZiXudRzteLTWaVNDPaOw/nVSdb6BEszcX6dpeMTMwzHuXyXrrKrmwyIRgeXjJpADz6FOpi7YFZrXB7VqcdQEQjaT7aFLhCZ5/HB+SS0/9bbQ3WPA3LM5VPjL7Rv4eOJAOLxPr9JX3pQNrowPTVEm/wPT7KlmNynSxyu+9zrKr90UwtOJzSGVRDG9WdpRV98id6He6R/PLKm+4UXOVtXDHmR0XyaLgyhQhoTleAgsmP4nz/edbHumj3mhO/mQHomHrWq7iuDD/nsA==\n    \n//    struct stat a;\n//    const char * path = '/Users/wt/pro';\n//    stat(path, &a);\n//    int abc = sizeof(a);\n//\n//    CLAuthorizationStatus status = [CLLocationManager authorizationStatus];\n//    NSLog(@\"%f\",[[NSDate date]timeIntervalSince1970]);\n//\n//\n//    [NSKeyedUnarchiver unarchiveObjectWithData:nil];\n//\n//    CCCrypt(kCCDecrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding|kCCOptionECBMode,)\n    return  0;\n}\n\nvoid test_aes(){\n    AES aes;\n    byte enc[16];\n    byte buf[16]=\"this is a test\";\n    byte ret[16];\n    aes.encrypt(buf,enc);\n    aes.decrypt(enc,ret);\n    printf(\"%s\",ret);\n}\n\n\nvoid test_folly()\n{\n    \n}\n\nvoid b(void)\n{\n    usleep(200 * 1000);\n}\n\nvoid a(void)\n{\n    for(int i=0; i<3; i++)\n    {\n        b();\n    }\n    NSString * sour = @\"abc\";\n    NSString * str = [[NSString alloc] initWithString:sour];\n    printf(\"Cycle\\n\");\n    NSLog(@\"%@\",str);\n}\n\nvoid c(int i);\nvoid d(int i)\n{\n    c(i-1);\n}\n\nvoid c(int i)\n{\n    if (i > 0) {\n        d(i);\n    }\n}\n\nvoid breakpoint(void)\n{\n    a();\n    c(1);\n}\n\nint test()\n{\n    while(true) {\n        breakpoint();\n    }\n    return 0;\n}\n\n\nint main(int argc, const char * argv[]) {\n    sleep(1);\n    test();\n//    test_fun();\n//    test_aes();\n    return 0;\n}\n"
  },
  {
    "path": "tools/verifyAlgorithm/test.py",
    "content": "#!/usr/bin/python3\n# -*- encoding: utf-8 -*-\n#@File    :   test.py\n#@Time    :   2021/07/29 15:15:38\n#@Author  :   wt \n\nfrom wtpytracer import *\n\n####################\n## command :\n##      python3 test.py ~/Desktop/1627533881instrace.log\n\n## 定义需要检测的 变量 : flag + '_' + 地址 + '_' + 寄存器\nCheck_0x10000393c_w8 = 'Check_0x10000393c_w8'\n\n\n### 翻译的测试代码\ndef f(x):\n    ret = 0\n    for index in range(x):\n        ret = ret + index\n        check_value(ret,Check_0x10000393c_w8) # check ret 和 0x10000393c 的 w8 的寄存器值\n    return ret + x\n\n\nif __name__ == '__main__':\n    import sys\n    args_list = sys.argv\n    if len(args_list) != 2 :\n        exit()\n    file_name = args_list[1]\n\n    try:\n        set_trace_data(Check_0x10000393c_w8)\n        parser_trace_log_file(file_name)\n        enable(CheckFunctionTracer())\n        f(5)\n    finally:\n        disable()\n"
  },
  {
    "path": "tools/verifyAlgorithm/wtpytracer.py",
    "content": "#!/usr/bin/python3\n# -*- encoding: utf-8 -*-\n#@File    :   wtpytracer.py\n#@Time    :   2021/07/27 18:17:18\n#@Author  :   wt \n\nimport re\nimport sys\nimport inspect\nfrom collections import OrderedDict\n\nclass TracebackFancy:\n    \n    def __init__(self, traceback):\n        self.t = traceback\n\n    def getFrame(self):\n        return FrameFancy(self.t.tb_frame)\n\n    def getLineNumber(self):\n        return self.t.tb_lineno if self.t is not None else None\n\n    def getNext(self):\n        return TracebackFancy(self.t.tb_next)\n\n    def __str__(self):\n        if self.t is None:\n            return \"\"\n        str_self = \"%s @ %s\" % (\n            self.getFrame().getName(), self.getLineNumber())\n        return str_self + \"\\n\" + self.getNext().__str__()\n\n\nclass ExceptionFancy:\n\n    def __init__(self, frame):\n        self.etraceback = frame.f_exc_traceback\n        self.etype = frame.exc_type\n        self.evalue = frame.f_exc_value\n\n    def __init__(self, tb, ty, va):\n        self.etraceback = tb\n        self.etype = ty\n        self.evalue = va\n\n    def getTraceback(self):\n        return TracebackFancy(self.etraceback)\n\n    def __nonzero__(self):\n        return self.etraceback is not None or self.etype is not None or self.evalue is not None\n\n    def getType(self):\n        return str(self.etype)\n\n    def getValue(self):\n        return self.evalue\n\n\nclass CodeFancy:\n\n    def __init__(self, code):\n        self.c = code\n\n    def getArgCount(self):\n        return self.c.co_argcount if self.c is not None else 0\n\n    def getFilename(self):\n        return self.c.co_filename if self.c is not None else \"\"\n\n    def getVariables(self):\n        return self.c.co_varnames if self.c is not None else []\n\n    def getName(self):\n        return self.c.co_name if self.c is not None else \"\"\n\n    def getFileName(self):\n        return self.c.co_filename if self.c is not None else \"\"\n\n\nclass ArgsFancy:\n\n    def __init__(self, frame, arginfo):\n        self.f = frame\n        self.a = arginfo\n\n    def __str__(self):\n        args, varargs, kwargs = self.getArgs(), self.getVarArgs(), self.getKWArgs()\n        ret = \"\"\n        count = 0\n        size = len(args)\n        for arg in args:\n            ret = ret + (\"%s = %s\" % (arg, args[arg]))\n            count = count + 1\n            if count < size:\n                ret = ret + \", \"\n        if varargs:\n            if size > 0:\n                ret = ret + \" \"\n            ret = ret + \"varargs are \" + str(varargs)\n        if kwargs:\n            if size > 0:\n                ret = ret + \" \"\n            ret = ret + \"kwargs are \" + str(kwargs)\n        return ret\n\n    def getNumArgs(wantVarargs=False, wantKWArgs=False):\n        args, varargs, keywords, values = self.a\n        size = len(args)\n        if varargs and wantVarargs:\n            size = size + len(self.getVarArgs())\n        if keywords and wantKWArgs:\n            size = size + len(self.getKWArgs())\n        return size\n\n    def getArgs(self):\n        args, _, _, values = self.a\n        argWValues = OrderedDict()\n        for arg in args:\n            argWValues[arg] = values[arg]\n        return argWValues\n\n    def getVarArgs(self):\n        _, vargs, _, _ = self.a\n        if vargs:\n            return self.f.f_locals[vargs]\n        return ()\n\n    def getKWArgs(self):\n        _, _, kwargs, _ = self.a\n        if kwargs:\n            return self.f.f_locals[kwargs]\n        return {}\n\nclass FrameFancy:\n    \n    def __init__(self, frame):\n        self.f = frame\n\n    def getCaller(self):\n        return FrameFancy(self.f.f_back)\n\n    def getLineNumber(self):\n        return self.f.f_lineno if self.f is not None else 0\n\n    def getCodeInformation(self):\n        return CodeFancy(self.f.f_code) if self.f is not None else None\n\n    def getExceptionInfo(self):\n        return ExceptionFancy(self.f) if self.f is not None else None\n\n    def getName(self):\n        return self.getCodeInformation().getName() if self.f is not None else \"\"\n\n    def getFileName(self):\n        return self.getCodeInformation().getFileName() if self.f is not None else \"\"\n\n    def getLocals(self):\n        return self.f.f_locals if self.f is not None else {}\n\n    def getArgumentInfo(self):\n        return ArgsFancy(\n            self.f, inspect.getargvalues(\n                self.f)) if self.f is not None else None\n\nclass TracerClass:\n    \n    def callEvent(self, frame):\n        pass\n\n    def lineEvent(self, frame):\n        pass\n\n    def returnEvent(self, frame, retval):\n        pass\n\n    def exceptionEvent(self, frame, exception, value, traceback):\n        pass\n\n    def cCallEvent(self, frame, cfunct):\n        pass\n\n    def cReturnEvent(self, frame, cfunct):\n        pass\n\n    def cExceptionEvent(self, frame, cfunct):\n        pass\n\ntracer_impl = TracerClass()\ndata_dic = {}\nold_trace_func = None\n\ndef parser_flag(flag):\n    import re\n    aa = re.split(r'_',flag)\n    if len(aa) != 3 :\n        return None,None\n    return aa[1],aa[2]\n\nclass CheckFunctionTracer():\n    def callEvent(self, frame):\n        if 'check_value' == frame.getName():\n            flag = frame.getArgumentInfo().getArgs()['check_flag']\n            value = frame.getArgumentInfo().getArgs()['value']\n            addr,register = parser_flag(flag)\n            if addr in data_dic and register in data_dic[addr]:\n                run_index = data_dic[addr][register]['run_index']\n                data_len = len(data_dic[addr][register]['data'])\n                if run_index >= data_len:\n                    print('*** err : at address : {} . run_index : {} out of rang'.format(addr,run_index))\n                    return\n                if value == data_dic[addr][register]['data']['{}'.format(run_index + 1)] :\n                    print('check : {} at {} times,match.'.format(addr,run_index + 1))\n                    data_dic[addr][register]['run_index'] = run_index + 1\n\n            # print(\"->>LoggingTracer : call \" + frame.getName() + \" from \" + frame.getCaller().getName() + \" @ \" + str(frame.getCaller().getLineNumber()) + \" args are \" + str(frame.getArgumentInfo()))\n\n\n\n# @ check_flag 为 携带了地址，和寄存器名称\n# @ value 为当前需要 check 的值\n# 在 sys.settracer设置的回调中，只接管此函数\ndef check_value(value,check_flag):\n    pass\n\n\ndef set_trace_data(check_flag):\n    global data_dic\n    addr,register = parser_flag(check_flag)\n    if not addr or not register :\n        print('err : check_flag is wrong.')\n        return\n    \n    if addr in data_dic:\n        data_dic[addr][register] = {\n            'data':{},\n            'run_index':0   \n        }\n    else:\n        addr_dic = {\n            register:{\n                'data':{},\n                'run_index':0\n            }\n        }\n        data_dic[addr] = addr_dic\n\n\ndef add_data_in_data_dic(addr,register,value):\n    global data_dic\n    cur_reg_dic = data_dic[addr][register]\n    data_len = len(cur_reg_dic['data'])\n    data_dic[addr][register]['data']['{}'.format(data_len + 1)] = value\n\ndef parser_trace_log_file(fileName):\n    global data_dic\n    file = open(fileName)\n    while True:\n        lines = file.readlines(100000)\n        if not lines:\n            break\n        for line in lines:\n            matchObj = re.match(r'\\s*(\\S+)\\s+',line,re.M|re.I)\n            if matchObj:\n                addr = str(matchObj.group()).replace(' ','')\n                if addr in data_dic:\n                    reg = data_dic[addr]\n                    for register in data_dic[addr].keys():\n                        register_out = re.findall(register +r'  : (\\S+)',line)\n                        if register_out:\n                            register_value = int(register_out[0],16)\n                            add_data_in_data_dic(addr,register,register_value)\n        \n    file.close()\n    # {'1234':{'1':0,\"2\":1}}  # flag : {...}  address:{'x0':{data:{},run_index:0},'x1':{data:{},run_index:0}}\n\n\ndef the_tracer_check_data(frame, event, args = None):\n    global data_dic\n    global tracer_impl\n\n    code = frame.f_code \n\n    func_name = code.co_name \n  \n    line_no = frame.f_lineno \n    if tracer_impl is None:\n        print('@@@ tracer_impl : None.')\n        return None\n\n    if event == 'call':\n        tracer_impl.callEvent(FrameFancy(frame))\n\n    return the_tracer_check_data\n\n\n\ndef enable(tracer_implementation=None):\n    global tracer_impl,old_trace_func\n    if tracer_implementation:\n        tracer_impl = tracer_implementation  # 传递 工厂实力的对象\n    old_trace_func = sys.gettrace()\n    sys.settrace(the_tracer_check_data) # 注册回调到系统中\n\n\ndef check_run_ok():\n    global data_dic\n    for addr,addr_dic in data_dic.items():\n        for _,reg_dic in addr_dic.items():\n            if reg_dic['run_index'] == len(reg_dic['data']):\n                print('->>> at {} check value is perfect.'.format(addr))\n            else:\n                print('*** err : at {} check {} times.'.format(addr,reg_dic['run_index']))\n\ndef disable():\n    check_run_ok()\n    global old_trace_func\n    sys.settrace(old_trace_func)\n    \n"
  }
]