SoftwareBreakpointManager.cpp
Go to the documentation of this file.
1 #include "StdAfx.h"
3 #include <bzscore/assert.h>
4 #include <MSP430_Debug.h>
5 
6 using namespace MSP430Proxy;
7 
8 MSP430Proxy::SoftwareBreakpointManager::SoftwareBreakpointManager( unsigned flashStart, unsigned flashEnd, unsigned short breakInstruction, bool instantCleanup )
9  : m_FlashStart(flashStart)
10  , m_FlashEnd(flashEnd)
11  , m_FlashSize(flashEnd - flashStart + 1)
12  , m_BreakInstruction(breakInstruction)
13  , m_bInstantCleanup(instantCleanup)
14 {
15  ASSERT(!(m_FlashSize & 1));
16  size_t segmentCount = (m_FlashSize + MAIN_SEGMENT_SIZE - 1) / MAIN_SEGMENT_SIZE;
17  m_Segments.resize(segmentCount);
18 }
19 
21 {
22  TranslatedAddr addr = TranslateAddress(rawAddr);
23  if (!addr.Valid)
24  return false;
25 
26  return m_Segments[addr.Segment].SetBreakpoint(addr.Offset);
27 }
28 
29 MSP430Proxy::SoftwareBreakpointManager::TranslatedAddr MSP430Proxy::SoftwareBreakpointManager::TranslateAddress( unsigned addr )
30 {
31  TranslatedAddr result;
32  result.Valid = false;
33 
34  addr &= ~1;
35 
36  if (addr < m_FlashStart)
37  return result;
38 
39  unsigned flashOff = addr - m_FlashStart;
40  if (flashOff >= m_FlashSize)
41  return result;
42 
43  result.Segment = flashOff / MAIN_SEGMENT_SIZE;
44  result.Offset = flashOff % MAIN_SEGMENT_SIZE;
45  result.Valid = true;
46 
47  return result;
48 }
49 
51 {
52  TranslatedAddr addr = TranslateAddress(rawAddr);
53  if (!addr.Valid)
54  return false;
55 
56  return m_Segments[addr.Segment].RemoveBreakpoint(addr.Offset);
57 }
58 
59 bool MSP430Proxy::SoftwareBreakpointManager::SegmentRecord::SetBreakpoint( unsigned offset )
60 {
61  switch(BpState[offset / 2])
62  {
63  case BreakpointActive:
64  case BreakpointPending:
65  return false; //Breakpoint is already set
66  case BreakpointInactive:
67  InactiveBreakpointCount--;
68  BpState[offset / 2] = BreakpointActive;
69  return true;
70  case NoBreakpoint:
71  PendingBreakpointCount++;
72  BpState[offset / 2] = BreakpointPending;
73  return true;
74  default:
75  return false;
76  }
77 }
78 
79 bool MSP430Proxy::SoftwareBreakpointManager::SegmentRecord::RemoveBreakpoint( unsigned offset )
80 {
81  switch(BpState[offset / 2])
82  {
83  case BreakpointActive:
84  InactiveBreakpointCount++;
85  BpState[offset / 2] = BreakpointInactive;
86  return true;
87  case BreakpointPending:
88  PendingBreakpointCount--;
89  BpState[offset / 2] = NoBreakpoint;
90  return true;
91  case BreakpointInactive:
92  case NoBreakpoint:
93  return false;
94  default:
95  return false;
96  }
97 }
98 
100 {
101  for (size_t i = 0; i < m_Segments.size(); i++)
102  {
103  if (!m_Segments[i].PendingBreakpointCount)
104  {
105  if (!m_bInstantCleanup || !m_Segments[i].InactiveBreakpointCount)
106  continue;
107  }
108 
109  unsigned segBase = m_FlashStart + i * MAIN_SEGMENT_SIZE;
110  unsigned short data[MAIN_SEGMENT_SIZE / 2], data2[MAIN_SEGMENT_SIZE / 2];
111  if (MSP430_Read_Memory(segBase, (char *)data, sizeof(data)) != STATUS_OK)
112  return false;
113 
114  bool eraseNeeded = false;
115 
116  for (size_t j = 0; j < MAIN_SEGMENT_SIZE / 2; j++)
117  {
118  switch(m_Segments[i].BpState[j])
119  {
120  case BreakpointInactive:
121  m_Segments[i].BpState[j] = NoBreakpoint;
122  data[j] = m_Segments[i].OriginalInstructions[j];
123  eraseNeeded = true;
124  break;
125  case BreakpointPending:
126  m_Segments[i].BpState[j] = BreakpointActive;
127  m_Segments[i].OriginalInstructions[j] = data[j];
128 
129  if ((data[j] & m_BreakInstruction) != m_BreakInstruction)
130  eraseNeeded = true;
131 
132  data[j] = m_BreakInstruction;
133  break;
134  }
135  }
136 
137  for (;;)
138  {
139  if (eraseNeeded)
140  {
141  if (MSP430_Erase(ERASE_MAIN, segBase, sizeof(data)) != STATUS_OK)
142  return false;
143  }
144 
145  if (MSP430_Write_Memory(segBase, (char *)data, sizeof(data)) != STATUS_OK)
146  return false;
147 
148  if (MSP430_Read_Memory(segBase, (char *)data2, sizeof(data2)) != STATUS_OK)
149  return false;
150 
151  if (memcmp(data, data2, sizeof(data)))
152  {
153  if (!eraseNeeded)
154  {
155  eraseNeeded = true;
156  continue;
157  }
158  return false;
159  }
160 
161  break;
162  }
163 
164  m_Segments[i].PendingBreakpointCount = 0;
165  m_Segments[i].InactiveBreakpointCount = 0;
166  }
167 
168  return true;
169 }
170 
172 {
173  TranslatedAddr addr = TranslateAddress(rawAddr);
174  if (!addr.Valid)
175  return NoBreakpoint;
176 
177  return (BreakpointState)m_Segments[addr.Segment].BpState[addr.Offset / 2];
178 }
179 
180 bool MSP430Proxy::SoftwareBreakpointManager::GetOriginalInstruction( unsigned rawAddr, unsigned short *pInsn )
181 {
182  TranslatedAddr addr = TranslateAddress(rawAddr);
183  if (!addr.Valid)
184  return false;
185 
186  switch (m_Segments[addr.Segment].BpState[addr.Offset / 2])
187  {
188  case BreakpointActive:
189  case BreakpointInactive:
190  *pInsn = m_Segments[addr.Segment].OriginalInstructions[addr.Offset / 2];
191  return true;
192  default:
193  return false;
194  }
195 }
196 
197 void MSP430Proxy::SoftwareBreakpointManager::HideOrRestoreBreakpointsInMemorySnapshot( unsigned addr, void *pBlock, size_t length, bool hideBreakpoints )
198 {
199  //Adjust pBlock so that it starts inside the FLASH region or past it
200  if (addr < m_FlashStart)
201  {
202  unsigned delta = m_FlashStart - addr;
203 
204  if (delta >= length)
205  return; //Nothing to do, the block does not cover any FLASH addresses
206 
207  addr += delta;
208  length -= delta;
209  pBlock = ((char *)pBlock + delta);
210  }
211 
212  int bufferOffsetInFlash = addr - m_FlashStart;
213 
214  size_t indexInBlock = 0;
215  for (size_t seg = bufferOffsetInFlash / MAIN_SEGMENT_SIZE; seg < m_Segments.size(); seg++)
216  {
217  unsigned baseAddr = m_FlashStart + seg * MAIN_SEGMENT_SIZE;
218 
219  size_t i = 0;
220  if (baseAddr < addr)
221  i = addr - baseAddr; //First segment covered by the block
222 
223  while (i < MAIN_SEGMENT_SIZE)
224  {
225  if (indexInBlock >= length)
226  return;
227 
228  switch(m_Segments[seg].BpState[i / 2])
229  {
230  case BreakpointActive:
231  case BreakpointInactive:
232  if (hideBreakpoints)
233  ((char *)pBlock)[indexInBlock] = ((char *)m_Segments[seg].OriginalInstructions)[i];
234  else
235  ((char *)m_Segments[seg].OriginalInstructions)[i] = ((char *)pBlock)[indexInBlock];
236  break;
237  }
238 
239  i++;
240  indexInBlock++;
241  }
242  }
243 }