Initial checkin of lldb code from internal Apple repo.

llvm-svn: 105619
diff --git a/lldb/tools/debugserver/source/FunctionProfiler.cpp b/lldb/tools/debugserver/source/FunctionProfiler.cpp
new file mode 100644
index 0000000..2fa57d3
--- /dev/null
+++ b/lldb/tools/debugserver/source/FunctionProfiler.cpp
@@ -0,0 +1,288 @@
+//===-- 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, &reg))
+            {
+                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<bytes_read; ++i)
+//                  {
+//                      printf(" %2.2x", buf[i]);
+//                  }
+//              }
+//              printf("\n");
+
+#elif defined (__powerpc__) || defined (__ppc__)
+
+                uint32_t opcode = 0;
+                if (DNBProcessMemoryRead(m_pid, pc, 4, &opcode) == 4)
+                {
+                    printf("0x%8.8x: 0x%8.8x\n", pc, opcode);
+                }
+
+#elif defined (__arm__)
+                #define CPSR_T (1u << 5)
+                // Read the CPSR into flags
+                if (DNBThreadGetRegisterValueByID(m_pid, tid, REGISTER_SET_GENERIC, GENERIC_REGNUM_FLAGS, &reg))
+                {
+                    const uint32_t flags = reg.value.uint32;
+
+                    const bool curr_pc_is_thumb = (flags & CPSR_T) != 0; // check the CPSR T bit
+                    const bool last_pc_was_thumb = (m_last_flags & CPSR_T) != 0; // check the CPSR T bit
+                    bool opcode_is_sequential = false;
+
+                    uint32_t opcode;
+                    // Always read four bytes for the opcode
+                    if (DNBProcessMemoryRead(m_pid, pc, 4, &opcode) == 4)
+                    {
+                        if (curr_pc_is_thumb)
+                        {
+                            // Trim off the high 16 bits if this is a 16 bit thumb instruction
+                            if ((opcode & 0xe000) != 0xe000 || (opcode & 0x1800) == 0)
+                            {
+                                opcode &= 0xFFFFu;
+                                printf("0x%8.8x: %4.4x     Thumb\n", pc, opcode);
+                            }
+                            else
+                                printf("0x%8.8x: %8.8x Thumb\n", pc, opcode);
+                        }
+                        else
+                            printf("0x%8.8x: %8.8x ARM\n", pc, opcode);
+                    }
+
+                    if (m_last_flags != 0 && curr_pc_is_thumb == last_pc_was_thumb)
+                    {
+                        if (curr_pc_is_thumb)
+                        {
+                            if (pc == m_last_pc + 2)
+                            {
+                                opcode_is_sequential = true;
+                            }
+                            else if (pc == m_last_pc + 4)
+                            {
+                                // Check for 32 bit thumb instruction...
+                                uint16_t opcode16;
+                                if (DNBProcessMemoryRead(m_pid, m_last_pc, 2, &opcode16) == 2)
+                                {
+                                    if ((opcode16 & 0xe000) == 0xe000 && (opcode16 & 0x1800) != 0)
+                                    {
+                                        // Last opcode was a 32 bit thumb instruction...
+                                        opcode_is_sequential = true;
+                                    }
+                                }
+                            }
+                        }
+                        else
+                        {
+                            if (pc == m_last_pc + 4)
+                            {
+                                opcode_is_sequential = true;
+                            }
+                        }
+                    }
+
+
+                    if (opcode_is_sequential)
+                    {
+                        m_consecutive_opcode_count++;
+                    }
+                    else
+                    {
+                        if (m_consecutive_opcode_count > 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;
+    }
+}