25 Commits

Author SHA1 Message Date
Adam Green
f10a89530b Upgrade MRI to version 1.5
This upgrades the version of the MRI library sources used by
KernelDebug and ThreadDebug to the latest that I am actively
supporting.

Changes that will benefit both ThreadDebug and KernelDebug include:
* I added the libraries/MRI/src/variants folder to hold the definition
  of g_memoryMapXml specific to each Arduino variant which supports
  MRI. Before these definitions were duplicated between ThreadDebug and
  KernelDebug.
* Has cache fix to enable soft breakpoints for code running out of RAM.
* Fixed cases where single stepping would sometimes hang if the code
  being stepped over caused a crash.
* I have added a DebugSerial object which can be used in place of
  Serial and/or SerialUSB to send output to the GDB console during the
  development process. MRI contains changes which make sending such
  output to GDB more efficient so I added this DebugSerial object to
  take advantage of it. The ThreadDebug example has been modified to
  show using this object to allow Serial.print() calls when
  using ThreadDebug which previously caused problems.

Some of the changes included in this version update will benefit
ThreadDebug:
* Platform_CommSendBuffer() is now overridden by ThreadDebug to send
  packets to GDB in one USB call instead of sending a byte at a
  time as it did before.
* The original RTX OS handlers like SVCall, PendSV, and SysTick only
  need to be saved once, during init, and not each time that
  ThreadDebug's versions are switched in.
* When running a test pass on ThreadDebug this time, I noticed that
  user threads weren't being locked as expected when I used the
  `set scheduler-locking step` command in GDB. I have always had this
  case in my test pass so I don't know how I didn't notice it was
  broken before. Anyway it is now fixed by making sure that the RTX
  idle thread is never allowed to remain frozen. If it has been
  requested by GDB to be frozen, it is thawed at one priority level
  higher than normal so that it stops all other frozen threads from
  running.

Other changes might not be a direct benefit to ThreadDebug but they
will be for KernelDebug:
* Faults will now pend to DebugMon so that invalid memory accesses
  initiated from GDB will no longer result in double fault CPU hard
  hangs. This pending to DebugMon for faults was actually copied from
  behavior first created for ThreadDebug back in 2020.
* Better handling of crashes the occur when the stack pointer becomes
  corrupted. Previously stacking exceptions could result in CPU hard
  hangs due to double faulting.
* Now has better code to handle single stepping through critical
  sections.
* Can now modify the current SP pointer from GDB. Probably not
  something most people would want to do though. Can also update the
  value of the PRIMASK, BASEPRI, FAULTMASK, and CONTROL special
  registers.

Other important updates to MRI included in version 1.5 are:
* Can now step into Standard C Library calls like memset() with no
  weird side effects.
* MRI now supports running the DebugMon interrupt handler at priorities
  other than 0. This allows important code such as USB or Bluetooth
  stacks to run in the background while GDB/MRI are debugging lower
  priority code. I first explored this ability for ThreadDebug but now
  use it in other projects to do things like communicate with GDB over
  BLE.
* Anywhere that the application under debug might want to call into
  MRI (semihosting, setting debugger hooks, etc), it now uses unique
  hardcoded `bkpt` instructions rather than just making function calls.
  This allows them to be called when MRI is installed as a separate
  boot loader on a device.
* Unescaping of binary packet data sent from GDB has been pushed lower
  down into the software stack, to the packet layer. This is where it
  should have been done in the first place.

Thanks go to @xiaoxiang781216, @icecream95, and @PetteriAimonen for
their MRI contributions that are included in this update.
2023-04-19 13:43:47 +02:00
Martino Facchin
42114ff7d0 Libraries: add mbed_giga explicit compatibility 2023-03-01 09:19:17 +01:00
Martino Facchin
a44431f453 Add relevant libraries to opta subarch 2022-12-12 18:35:33 +01:00
giulcioffi
7256328964 Add mbed_nicla architecture to core libraries 2022-03-07 12:03:57 +01:00
Martino Facchin
92f7f53c27 Libraries: fix various misleading library.properties 2021-10-05 18:35:27 +02:00
Martino Facchin
e93d792853 Portenta: split flash via menus
* Relocate SDRAM at 0x60000000 to make it executable without touching the MPU
* Patch mbed-os-to-arduino to automatically patch the linker scripts
2021-09-21 16:11:47 +02:00
dcuartielles
cce752cd83 Added Nano 33 BLE 2021-05-07 16:01:13 +02:00
Martino Facchin
f757d6e0c1 ThreadDebug: shadow SerialUSB arduino object with mbed's internal 2021-03-29 15:30:06 +02:00
Martino Facchin
7a8d3ee462 Speedup compilation by making singletons opaque 2021-03-17 15:53:20 +01:00
Martino Facchin
f7d5da81e5 Merge pull request #61 from facchinm/rpc_threaddebug
RPC improvements and other goodies
2020-10-06 18:21:24 +02:00
Adam Green
d6dc209cf8 Fix ThreadDebug warnings when building for nRF52*
The Nordic headers already publicly define ASSERT and ARRAY_SIZE
macros. #undef them and then define the ones custom to the
ThreadDebug.o module instead.
2020-10-02 22:27:06 -07:00
Martino Facchin
3cf5b88b0e RPC: introduce SerialRPC abstraction over normal (non raw) channels 2020-09-30 12:36:28 +02:00
Martino Facchin
a265a6c94c WIP: use RPC lib as transport 2020-09-30 12:36:28 +02:00
Martino Facchin
4bdf4c12f5 ThreadDebug: add memory definition for nRF52840 2020-09-04 10:52:37 +02:00
Martino Facchin
73d4edb278 Fix examples documentation for MRI libraries 2020-05-19 12:41:22 +02:00
Martino Facchin
2d18d511e4 ThreadDebug: remove unnecessary mbed.h include 2020-05-18 15:06:45 +02:00
Adam Green
1dbfa6a0d1 Fix vCont multi-threading support
Updates MRI core to version 1.1-20200510-0.

Refactored the vCont multi-threading support again to better handle any
combination of continue and/or stepping actions that are sent from GDB
in a single vCont command. This includes a modification to requirements
for ports implementing Platform_RtosSetThreadState() to now support a
thread-id of MRI_PLATFORM_ALL_FROZEN_THREADS. This new special
thread-id indicates to the port that it should update the state of any
threads still in the initial frozen state after the previously parsed
vCont actions have been applied. Ports now also have to implement a
Platform_RtosRestorePrevThreadState() API to restore the state of the
threads to match the way they were configured after the last exit from
mriDebugException(). This is used to restore the thawed/single-stepping
state of threads while stepping through a range of addresses. This
pushes the responsibility to know how each thread was configured at the
beginning of a ranged single step onto the port instead of the MRI core
where it tried to maintain it unsuccessfully before.

The big change in this commit is that vCont now parses its parameters
twice when a port supports Platform_RtosSetThreadState(). On the first
pass it is checking for parsing errors and determining the most
specific continue or single step action to apply to the currently
halted thread. This action is used to determine if the halted thread
should be advanced past a hard coded breakpoint and if single stepping
over a hardcoded breakpoint on the halted thread, it is enough to send
GDB a T packet and continue GDB command handling rather than actually
continuing execution in single step mode. The second pass is used to
call the Platform_RtosSetThreadState() for each action encountered in
the vCont command from GDB, letting the port's implementation manage
the resulting list of states for all of the threads and the MRI core
only needs to remember if it needs to enable single stepping or not.
This makes it much easier to handle an arbirary list of actions sent
from GDB and the core now needs to make very few assumptions about the
nature of the action lists (the count, order, combination of continue
and single step, etc).

I did need to increase the size of the mriDebuggerStack as the vCont
handler itself now uses 100 bytes of stack while parsing the action
list sent by GDB.

Only fill mriCortexMDebuggerStack @ init. Was previously filling it
before every entry into MRI but really only needs to be done once from
mriCortexMInit().

I also made some other KernelDebug/ThreadDebug updates while code
reviewing and running a test pass on the latest MRI updates:
* Renamed the DEBUG_*_BREAK_ON_SETUP defines to DEBUG_*_BREAK_IN_SETUP.
* Cleaned up some comments in the ThreadDebug sources.
* I decreased IDLE_THREAD_STACK_SIZE to free up space that was found to
  not be required by mriIdle() thread while running the test pass.
* Switched ThreadList::findThreadId() to use a binary search instead of
  a linear search.
* mriDebugMonitorHandler() always checks to see if it needs to
  re-enable DTW/FPB. There is no reason to skip this check.
* Added a g_controlC flag in addition to the control C flag in MRI
  itself since the flag in MRI doesn't get cleared until leaving
  mriDebugException(). There were race conditions that as breakpoints
  were enabled by GDB, they would fire and mriDebugMonitorHandler()
  would think that CTRL+C had just been sent when it hadn't.
* Related to the previous item, I updated mriDebugMonitorHandler() to
  ignore debug events that occur while inside MRI since GDB itself may
  read from addresses on which it has read watchpoints and we want to
  ignore such debug events.
2020-05-11 20:13:15 -07:00
Adam Green
c541772d61 Improve vCont multi-threading support
Updates MRI core to version 1.1-20200506-0.

Added Platform_RtosSetThreadState() API to allow GDB to freeze
threads other than the one currently being single stepped via the
"set scheduler-locking step" command. The MRI core will only use
this new function if Platform_RtosIsSetThreadStateSupported()
return a non-zero value. Otherwise single stepping will silently
ignore an attempt to single step any thread other than the one
which caused the current halt and whether other threads are resumed
while single stepping is determined by the port implementor (usually
they would be resumed as that is the default behaviour expected by
GDB).

I moved alot of the thread tracking functionality of ThreadDebug into
the newly created ThreadList structure. It tracks the thread ids of the
active threads, their original priorities before being lowered to
osPriorityIdle to halt them during debugging, and their frozen/thawed/
single-stepping state. It ping pongs between g_pCurrThreadList and
g_pPrevThreadList so that it can reference the previously known
priority levels as the current priorities might still be those set by
the debugger if GDB requested that they be left frozen while single
stepping another thread.

I moved the call to restoreRtxHandlers() down into the DebugMon handler
before it attempts to awaken mriMain() rather than doing it in
mriMain() just after it awakens. This fixed an infinite loop that could
occur during certain single stepping operations:
* Single step debug event doesn't occur because that particular thread
  isn't scheduled by the RTOS.
* CTRL+C is pressed by the user to force a break.
* Communication channel see the CTRL+C and pends a DebugMon interrupt.
* DebugMon interrupt attempts to wake up mriMain() by signalling the
  MRI_THREAD_DEBUG_EVENT_FLAG flag. This will cause RTX to PendSV.
* When DebugMon handler returns, PendSV handler will execute in an
  attempt to switch the current context over to mriMain thread. This
  handler is hooked though for single stepping by ThreadDebug which
  means that it will pend a DebugMon interrupt again and so enters the
  infinite loop.
With my new fix, the PendSv hook is removed before DebugMon returns so
that the PendSv handler can run without pending yet another interrupt
into DebugMon.

The mriThreadSingleStepThreadId global is now set by
Platform_RtosSetThreadState() when the MRI core sets the state of a
thread to MRI_PLATFORM_THREAD_SINGLE_STEPPING. This allows GDB to
single step a thread other than the one which originally caused the
halt.

I updated Platform_RtosGetExtraThreadInfo() and
Platform_RtosGetThreadContext() in ThreadDebug to return NULL if the
specified thread-id isn't in the current g_pCurrThreadList. This fixes
a memory fault that was being generated by ThreadDebug when GDB would
first connect. When GDB first connects its sends a Hg0 command which
resulted in a call to Platform_RtosGetThreadContext() with a thread-id
of 0. The previous code would start trying to build up a register
context based off of this NULL pointer which was a bad thing.

I updated mriDebugException() to replay the calls to
Platform_RtosSetThreadState() before it makes an early exit for
situations like PC still being in the specified range during a ranged
single step operation. This allows ThreadDebug to make sure that its
g_pCurrThreadList object is always updated to the correct state before
it allows execution of the debuggee to continue.

I modified the behaviour of ranged single step to only skip the first
hardcoded breakpoint in the range whereas before it would skip all
breakpoints that were found within the range.

Now returns an error if GDB specifies more than one single step or more
than one continue action in a single vCont command. This assumption
makes the implementation of the vCont command much simpler and matches
the behaviour that I have seen from GDB so far.
2020-05-07 13:27:53 -07:00
Adam Green
72cc7d462a Add mriIdle() thread
When the debug monitor is active, this thread will take the place of
RTX's idle thread which will be suspended like other application
threads. The mriIdle thread will be suspended again before the
application's threads are resumed so it is only used in place of
RTX's idle thread when halted in GDB.

This change was made so that RTX's idle thread can be treated like any
other application thread which means that GDB is allowed to break into
it if nothing else is running. Without this change, it wouldn't make
sense to break into the code when nothing was actively running and
the idle thread was active since it was a thread that ThreadDebug
wasn't allowed to suspend.
2020-05-07 13:27:53 -07:00
Adam Green
3551e7bde3 Dynamically allocate thread arrays in constructor
Previously the ThreadDebug class allocated a fixed amount of storage to
track the list of active threads. This commit has the ThreadDebug
constructor now take an optional parameter, indicating
the maximum number of threads a developer expects to handle. It
defaults to 32.

I had thought about automatically growing these arrays as needed but
having a debug monitor dynamically allocating memory in a crash
scenario might just make a bad situation worse.

I also thought about just truncating the list if it was too small but
that introduced a bunch of special case handling in the code to deal
with scenarios such as:
* Important application threads not being suspended while halted in
  the debugger.
* GDB not finding the halted thread in the truncated list of threads.
* etc.
I just left in the ASSERT which dumps a message to Serial and then
enters an infinite loop if the arrays are too small to track all of
the active threads.
2020-05-07 13:27:53 -07:00
Adam Green
6878549a98 Cleanup thread suspension code
Previously I was using the osThreadSuspend() and osThreadResume() APIs
to freeze and thaw the application threads during debug halt. I code
reviewed the RTX implementation of osThreadResume() and noticed that it
incorrectly resumed previously waiting threads to the ready state. The
code now suspends the application threads by lowering their priority to
osPriorityIdle and then elevating the priority of the idle thread to
osPriorityIdle+1 so the idle thread runs instead of an application
thread if a debugger related thread blocks. I would have liked to use
priority level 0 for the application threads which would have placed
them below the idle thread but the osThreadSetPriority() API returns
an error for this.

I now run the mriMain() thread at osPriorityISR while it is suspending
and resuming application threads as it is the highest priority level
accepted by the osThreadSetPriority().

Always resume all threads when leaving debug halt mode, even when
single stepping. Previously it only thawed the single stepping thread
but that didn't match the GDB remote stub specification for stop
mode debugging.
2020-05-07 13:27:53 -07:00
Adam Green
da8ed66a89 Add GDB thread command support
This commit updates the MRI core to version 1.1.20200413.0 which now
includes support for GDB thread commands. It also provides the required
implementations of the Platform_Rtos*() functions for ThreadDebug and
KernelDebug to enable that new thread support in each of those debug
monitors.

Changes to the MRI core include:
* Improve T packet response - Added support for notifying GDB of
  current thread id, if running in a RTOS environment, and expanding on
  the cause of debug trap stops to let GDB know which watchpoint, if
  any, was the cause.
* vCont support - This commit adds support for single stepping,
  continuing, and ranged single stepping in single and multi threaded
  environments. The ranged single stepping is a really cool feature that
  reduces the round trip traffic that usually occurs between MRI and GDB
  when single stepping through code at source code level. Ranged single
  stepping will just continue execution on each single stepped
  instruction that corresponds to the current source code line and only
  send a T stop response to GDB when the program counter points to an
  instruction not in the range of the current source code line.
* Implement qf/sThreadInfo request to list threads to GDB - Allows MRI
  to respond to GDB's qfThreadInfo & qsThreadInfo requests with a list
  of the RTOS thread IDs.
* Added qThreadExtraInfo support - Allows GDB to call and retrieve
  extra information about a particular thread ID as a string. For RTX,
  it currently returns the thread name and its state (running, waiting,
  etc.)
* Add support for Hg command - GDB sends this command to indicate which
  thread's registers should be reference by the next 'g' or 'G'
  command. Renamed the ScatterGather class to MriContext and now use it
  from the higher level MRI core code to access the CPU register
  contents. When Hg is sent, MRI will switch the RTX thead context used
  for future register read and write operations.
* Added support for the T command - The T command is sent by GDB to see
  if a particular thread ID is still active or not. GDB sends this
  command to a remote stub when the user types the "thread id#" command
  into the user interface to see if the specified ID is valid or not.
2020-05-07 13:27:53 -07:00
Adam Green
25d4290fd7 Add detach and monitor support
The "detach" command allows GDB to detach from a running program linked
with MRI. It causes the debuggee to resume execution and then the user
can exit GDB with the program on the embedded device in a running state
whereas today it would remain halted when GDB disconnects.

Added support for the following "monitor" commands:
* "monitor help" - Lists the currently supported monitor commands to
  the GDB console. Issuing an unknown monitor command will also display
  this help list.
* "monitor showfault" - This command will dump information about the
  current fault to the GDB console just like what happens if already
  connected when the fault occurs. This is useful if you are attaching
  GDB after the fault happens.
* "monitor reset" - After issuing this command in GDB the
  microcontroller will reset on the next "continue" or "detach". This
  doesn't work well when using USBSerial as the debug interface since
  the reset will cause the TTY device being used by GDB to briefly
  disappear during the reset, causing GDB to disconnect. The user
  needs to reissue the appropriate "target remote /dev/tty*" to make
  the connection again.

I needed to implement mriPlatform_CommHasTransmitCompleted() API for
both ThreadDebug and KernelDebug to indicate if the last text
transmitted has been sent. This is needed to make sure that the ack
for the "continue" command is sent back to GDB before the device is
actually reset or GDB gets confused.
2020-05-07 13:27:53 -07:00
Adam Green
cdfd2a1ae4 Make it easier to see which threads aren't suspended
I have created a g_threadNamesToIgnore[] array at the top of
ThreadDebug.cpp listing the names of the threads not to be suspended
when a debug event occurs. Currently the list only contains "rtx_idle".
Before the list was hardcoded in the suspendAllApplicationThreads()
function, where it was hard for maintainers to find.
2020-05-07 13:27:53 -07:00
Adam Green
e383a51d9b Modify debugger source file layout/naming
Previously, both the thread and kernel mode debug monitor libraries
contained a copy of the MRI core sources. Now the MRI sources are in
their own MRI library while the kernel and thread debugging libraries
just make use of the MRI library to get the core functionality. This
commit also renames these debugging libraries to:
    KernelDebug
        -and-
    ThreadDebug

I also went through both the kernel and thread mode debugging code
bases to clean them up and make them more consistent with one another.
This included comment cleanup.
2020-05-07 13:27:53 -07:00