//===-- FunctionProfiler.cpp ------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // Created by Greg Clayton on 10/8/08. // //===----------------------------------------------------------------------===// #include "FunctionProfiler.h" // C Includes // C++ Includes // Other libraries and framework includes #include "DNB.h" // Project includes //---------------------------------------------------------------------- // FunctionProfiler constructor //---------------------------------------------------------------------- FunctionProfiler::FunctionProfiler(nub_addr_t start_addr, nub_addr_t stop_addr) : m_pid(INVALID_NUB_PROCESS), m_start_addr(start_addr), m_stop_addr(stop_addr), m_start_break_id(INVALID_NUB_BREAK_ID), m_stop_break_id(INVALID_NUB_BREAK_ID), m_func_entered_count(0), m_last_pc(0), m_last_flags(0), m_consecutive_opcode_count(0), m_total_opcode_count(0) { } FunctionProfiler::~FunctionProfiler() { Clear(); } void FunctionProfiler::Clear() { if (m_pid != INVALID_NUB_PROCESS) { if (m_start_break_id != INVALID_NUB_BREAK_ID) DNBBreakpointClear(m_pid, m_start_break_id); if (m_stop_break_id != INVALID_NUB_BREAK_ID) DNBBreakpointClear(m_pid, m_stop_break_id); } m_start_break_id = INVALID_NUB_BREAK_ID; m_stop_break_id = INVALID_NUB_BREAK_ID; m_func_entered_count = 0; m_last_pc = 0; m_last_flags = 0; m_consecutive_opcode_count = 0; } void FunctionProfiler::Initialize(nub_process_t pid) { //printf("FunctionProfiler::%s(0x%4.4x)\n", __FUNCTION__, pid); Clear(); m_pid = pid; } #include "DNBDataRef.h" void FunctionProfiler::SetBreakpoints() { #if defined (__i386__) nub_size_t bp_opcode_size = 1; #elif defined (__powerpc__) || defined (__ppc__) nub_size_t bp_opcode_size = 4; #endif if (m_start_addr != INVALID_NUB_ADDRESS && !NUB_BREAK_ID_IS_VALID(m_start_break_id)) { #if defined (__arm__) m_start_break_id = DNBBreakpointSet(m_pid, m_start_addr & 0xFFFFFFFEu, m_start_addr & 1 ? 2 : 4, false); #else m_start_break_id = DNBBreakpointSet(m_pid, m_start_addr, bp_opcode_size, false); #endif if (NUB_BREAK_ID_IS_VALID(m_start_break_id)) DNBBreakpointSetCallback(m_pid, m_start_break_id, FunctionProfiler::BreakpointHitCallback, this); } if (m_stop_addr != INVALID_NUB_ADDRESS && !NUB_BREAK_ID_IS_VALID(m_stop_break_id)) { #if defined (__arm__) m_stop_break_id = DNBBreakpointSet(m_pid, m_stop_addr & 0xFFFFFFFEu, m_stop_addr & 1 ? 2 : 4, false); #else m_stop_break_id = DNBBreakpointSet(m_pid, m_stop_addr, bp_opcode_size, false); #endif if (NUB_BREAK_ID_IS_VALID(m_stop_break_id)) DNBBreakpointSetCallback(m_pid, m_stop_break_id, FunctionProfiler::BreakpointHitCallback, this); } } nub_bool_t FunctionProfiler::BreakpointHitCallback(nub_process_t pid, nub_thread_t tid, nub_break_t breakID, void *baton) { printf("FunctionProfiler::%s(pid = %4.4x, tid = %4.4x, breakID = %u, baton = %p)\n", __FUNCTION__, pid, tid, breakID, baton); return ((FunctionProfiler*) baton)->BreakpointHit(pid, tid, breakID); } nub_bool_t FunctionProfiler::BreakpointHit(nub_process_t pid, nub_thread_t tid, nub_break_t breakID) { printf("FunctionProfiler::%s(pid = %4.4x, tid = %4.4x, breakID = %u)\n", __FUNCTION__, pid, tid, breakID); if (breakID == m_start_break_id) { m_func_entered_count++; printf("FunctionProfiler::%s(pid = %4.4x, tid = %4.4x, breakID = %u) START breakpoint hit (%u)\n", __FUNCTION__, pid, tid, breakID, m_func_entered_count); } else if (breakID == m_stop_break_id) { if (m_func_entered_count > 0) m_func_entered_count--; printf("FunctionProfiler::%s(pid = %4.4x, tid = %4.4x, breakID = %u) STOP breakpoint hit (%u)\n", __FUNCTION__, pid, tid, breakID, m_func_entered_count); } return true; } void FunctionProfiler::ProcessStateChanged(nub_state_t state) { // printf("FunctionProfiler::%s(%s)\n", __FUNCTION__, DNBStateAsString(state)); switch (state) { case eStateInvalid: case eStateUnloaded: case eStateAttaching: case eStateLaunching: break; case eStateDetached: case eStateExited: // No sense is clearing out breakpoints if our process has exited... m_start_break_id = INVALID_NUB_BREAK_ID; m_stop_break_id = INVALID_NUB_BREAK_ID; printf("[0x%8.8x - 0x%8.8x) executed %u total opcodes.\n", m_total_opcode_count); break; case eStateStopped: // Keep trying find dyld each time we stop until we do if (!NUB_BREAK_ID_IS_VALID(m_start_break_id)) SetBreakpoints(); if (ShouldStepProcess()) { // TODO: do logging/tracing here nub_thread_t tid = DNBProcessGetCurrentThread(m_pid); DNBRegisterValue reg; m_total_opcode_count++; if (DNBThreadGetRegisterValueByID(m_pid, tid, REGISTER_SET_GENERIC, GENERIC_REGNUM_PC, ®)) { const nub_addr_t pc = reg.value.uint32; #if defined (__i386__) uint8_t buf[16]; uint32_t bytes_read = DNBProcessMemoryRead(m_pid, pc, 1, buf); if (bytes_read == 1) printf("0x%8.8x: %2.2x\n", pc, buf[0]); else printf("0x%8.8x: error: can't read opcode byte.\n", pc); // if (bytes_read > 0) // { // for (uint32_t i=0; i 0) { // printf(" x %u\n", m_consecutive_opcode_count); } m_consecutive_opcode_count = 1; //printf("0x%8.8x: %-5s", pc, curr_pc_is_thumb ? "Thumb" : "ARM"); //fflush(stdout); } m_last_flags = flags; } #else #error undefined architecture #endif m_last_pc = pc; } } break; case eStateRunning: case eStateStepping: case eStateCrashed: case eStateSuspended: break; default: break; } }