blob: 2fa57d3a770775d76c56d371f2c15c4857860289 [file] [log] [blame]
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001//===-- FunctionProfiler.cpp ------------------------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// Created by Greg Clayton on 10/8/08.
11//
12//===----------------------------------------------------------------------===//
13
14#include "FunctionProfiler.h"
15
16// C Includes
17// C++ Includes
18// Other libraries and framework includes
19#include "DNB.h"
20
21// Project includes
22
23//----------------------------------------------------------------------
24// FunctionProfiler constructor
25//----------------------------------------------------------------------
26FunctionProfiler::FunctionProfiler(nub_addr_t start_addr, nub_addr_t stop_addr) :
27 m_pid(INVALID_NUB_PROCESS),
28 m_start_addr(start_addr),
29 m_stop_addr(stop_addr),
30 m_start_break_id(INVALID_NUB_BREAK_ID),
31 m_stop_break_id(INVALID_NUB_BREAK_ID),
32 m_func_entered_count(0),
33 m_last_pc(0),
34 m_last_flags(0),
35 m_consecutive_opcode_count(0),
36 m_total_opcode_count(0)
37{
38}
39
40
41FunctionProfiler::~FunctionProfiler()
42{
43 Clear();
44}
45
46
47void
48FunctionProfiler::Clear()
49{
50 if (m_pid != INVALID_NUB_PROCESS)
51 {
52 if (m_start_break_id != INVALID_NUB_BREAK_ID)
53 DNBBreakpointClear(m_pid, m_start_break_id);
54 if (m_stop_break_id != INVALID_NUB_BREAK_ID)
55 DNBBreakpointClear(m_pid, m_stop_break_id);
56 }
57 m_start_break_id = INVALID_NUB_BREAK_ID;
58 m_stop_break_id = INVALID_NUB_BREAK_ID;
59 m_func_entered_count = 0;
60 m_last_pc = 0;
61 m_last_flags = 0;
62 m_consecutive_opcode_count = 0;
63}
64
65void
66FunctionProfiler::Initialize(nub_process_t pid)
67{
68 //printf("FunctionProfiler::%s(0x%4.4x)\n", __FUNCTION__, pid);
69 Clear();
70 m_pid = pid;
71}
72
73#include "DNBDataRef.h"
74
75void
76FunctionProfiler::SetBreakpoints()
77{
78#if defined (__i386__)
79 nub_size_t bp_opcode_size = 1;
80#elif defined (__powerpc__) || defined (__ppc__)
81 nub_size_t bp_opcode_size = 4;
82#endif
83 if (m_start_addr != INVALID_NUB_ADDRESS && !NUB_BREAK_ID_IS_VALID(m_start_break_id))
84 {
85#if defined (__arm__)
86 m_start_break_id = DNBBreakpointSet(m_pid, m_start_addr & 0xFFFFFFFEu, m_start_addr & 1 ? 2 : 4, false);
87#else
88 m_start_break_id = DNBBreakpointSet(m_pid, m_start_addr, bp_opcode_size, false);
89#endif
90 if (NUB_BREAK_ID_IS_VALID(m_start_break_id))
91 DNBBreakpointSetCallback(m_pid, m_start_break_id, FunctionProfiler::BreakpointHitCallback, this);
92 }
93 if (m_stop_addr != INVALID_NUB_ADDRESS && !NUB_BREAK_ID_IS_VALID(m_stop_break_id))
94 {
95#if defined (__arm__)
96 m_stop_break_id = DNBBreakpointSet(m_pid, m_stop_addr & 0xFFFFFFFEu, m_stop_addr & 1 ? 2 : 4, false);
97#else
98 m_stop_break_id = DNBBreakpointSet(m_pid, m_stop_addr, bp_opcode_size, false);
99#endif
100 if (NUB_BREAK_ID_IS_VALID(m_stop_break_id))
101 DNBBreakpointSetCallback(m_pid, m_stop_break_id, FunctionProfiler::BreakpointHitCallback, this);
102 }
103}
104
105nub_bool_t
106FunctionProfiler::BreakpointHitCallback(nub_process_t pid, nub_thread_t tid, nub_break_t breakID, void *baton)
107{
108 printf("FunctionProfiler::%s(pid = %4.4x, tid = %4.4x, breakID = %u, baton = %p)\n", __FUNCTION__, pid, tid, breakID, baton);
109 return ((FunctionProfiler*) baton)->BreakpointHit(pid, tid, breakID);
110}
111
112nub_bool_t
113FunctionProfiler::BreakpointHit(nub_process_t pid, nub_thread_t tid, nub_break_t breakID)
114{
115 printf("FunctionProfiler::%s(pid = %4.4x, tid = %4.4x, breakID = %u)\n", __FUNCTION__, pid, tid, breakID);
116 if (breakID == m_start_break_id)
117 {
118 m_func_entered_count++;
119 printf("FunctionProfiler::%s(pid = %4.4x, tid = %4.4x, breakID = %u) START breakpoint hit (%u)\n", __FUNCTION__, pid, tid, breakID, m_func_entered_count);
120 }
121 else if (breakID == m_stop_break_id)
122 {
123 if (m_func_entered_count > 0)
124 m_func_entered_count--;
125 printf("FunctionProfiler::%s(pid = %4.4x, tid = %4.4x, breakID = %u) STOP breakpoint hit (%u)\n", __FUNCTION__, pid, tid, breakID, m_func_entered_count);
126 }
127 return true;
128}
129
130void
131FunctionProfiler::ProcessStateChanged(nub_state_t state)
132{
133// printf("FunctionProfiler::%s(%s)\n", __FUNCTION__, DNBStateAsString(state));
134
135 switch (state)
136 {
137 case eStateInvalid:
138 case eStateUnloaded:
139 case eStateAttaching:
140 case eStateLaunching:
141 break;
142
143 case eStateDetached:
144 case eStateExited:
145 // No sense is clearing out breakpoints if our process has exited...
146 m_start_break_id = INVALID_NUB_BREAK_ID;
147 m_stop_break_id = INVALID_NUB_BREAK_ID;
148 printf("[0x%8.8x - 0x%8.8x) executed %u total opcodes.\n", m_total_opcode_count);
149 break;
150
151 case eStateStopped:
152 // Keep trying find dyld each time we stop until we do
153 if (!NUB_BREAK_ID_IS_VALID(m_start_break_id))
154 SetBreakpoints();
155
156 if (ShouldStepProcess())
157 {
158
159 // TODO: do logging/tracing here
160 nub_thread_t tid = DNBProcessGetCurrentThread(m_pid);
161 DNBRegisterValue reg;
162 m_total_opcode_count++;
163
164 if (DNBThreadGetRegisterValueByID(m_pid, tid, REGISTER_SET_GENERIC, GENERIC_REGNUM_PC, &reg))
165 {
166 const nub_addr_t pc = reg.value.uint32;
167
168#if defined (__i386__)
169 uint8_t buf[16];
170 uint32_t bytes_read = DNBProcessMemoryRead(m_pid, pc, 1, buf);
171 if (bytes_read == 1)
172 printf("0x%8.8x: %2.2x\n", pc, buf[0]);
173 else
174 printf("0x%8.8x: error: can't read opcode byte.\n", pc);
175
176// if (bytes_read > 0)
177// {
178// for (uint32_t i=0; i<bytes_read; ++i)
179// {
180// printf(" %2.2x", buf[i]);
181// }
182// }
183// printf("\n");
184
185#elif defined (__powerpc__) || defined (__ppc__)
186
187 uint32_t opcode = 0;
188 if (DNBProcessMemoryRead(m_pid, pc, 4, &opcode) == 4)
189 {
190 printf("0x%8.8x: 0x%8.8x\n", pc, opcode);
191 }
192
193#elif defined (__arm__)
194 #define CPSR_T (1u << 5)
195 // Read the CPSR into flags
196 if (DNBThreadGetRegisterValueByID(m_pid, tid, REGISTER_SET_GENERIC, GENERIC_REGNUM_FLAGS, &reg))
197 {
198 const uint32_t flags = reg.value.uint32;
199
200 const bool curr_pc_is_thumb = (flags & CPSR_T) != 0; // check the CPSR T bit
201 const bool last_pc_was_thumb = (m_last_flags & CPSR_T) != 0; // check the CPSR T bit
202 bool opcode_is_sequential = false;
203
204 uint32_t opcode;
205 // Always read four bytes for the opcode
206 if (DNBProcessMemoryRead(m_pid, pc, 4, &opcode) == 4)
207 {
208 if (curr_pc_is_thumb)
209 {
210 // Trim off the high 16 bits if this is a 16 bit thumb instruction
211 if ((opcode & 0xe000) != 0xe000 || (opcode & 0x1800) == 0)
212 {
213 opcode &= 0xFFFFu;
214 printf("0x%8.8x: %4.4x Thumb\n", pc, opcode);
215 }
216 else
217 printf("0x%8.8x: %8.8x Thumb\n", pc, opcode);
218 }
219 else
220 printf("0x%8.8x: %8.8x ARM\n", pc, opcode);
221 }
222
223 if (m_last_flags != 0 && curr_pc_is_thumb == last_pc_was_thumb)
224 {
225 if (curr_pc_is_thumb)
226 {
227 if (pc == m_last_pc + 2)
228 {
229 opcode_is_sequential = true;
230 }
231 else if (pc == m_last_pc + 4)
232 {
233 // Check for 32 bit thumb instruction...
234 uint16_t opcode16;
235 if (DNBProcessMemoryRead(m_pid, m_last_pc, 2, &opcode16) == 2)
236 {
237 if ((opcode16 & 0xe000) == 0xe000 && (opcode16 & 0x1800) != 0)
238 {
239 // Last opcode was a 32 bit thumb instruction...
240 opcode_is_sequential = true;
241 }
242 }
243 }
244 }
245 else
246 {
247 if (pc == m_last_pc + 4)
248 {
249 opcode_is_sequential = true;
250 }
251 }
252 }
253
254
255 if (opcode_is_sequential)
256 {
257 m_consecutive_opcode_count++;
258 }
259 else
260 {
261 if (m_consecutive_opcode_count > 0)
262 {
263 // printf(" x %u\n", m_consecutive_opcode_count);
264 }
265 m_consecutive_opcode_count = 1;
266 //printf("0x%8.8x: %-5s", pc, curr_pc_is_thumb ? "Thumb" : "ARM");
267 //fflush(stdout);
268 }
269 m_last_flags = flags;
270 }
271#else
272#error undefined architecture
273#endif
274 m_last_pc = pc;
275 }
276 }
277 break;
278
279 case eStateRunning:
280 case eStateStepping:
281 case eStateCrashed:
282 case eStateSuspended:
283 break;
284
285 default:
286 break;
287 }
288}