-
Notifications
You must be signed in to change notification settings - Fork 243
Multi core debugging
WORK IN PROGRESS -- We are currently updating VSCode to add better multi-core debugging which requires handling multiple debug sessions in one instance of VSCode. Multiple sessions can be independent of multi-core but from a look and feel the feel similar. Multiple sessions can be used using a Launch Group or Compound Launch and they can work. There are a couple of issues with debugging the type of targets we deal with
- All launches are done near simultaneously. Usually, there is a dependency but no dependency can be enforced (not easily anyway)
- Information may need to be passed between instances about TCP ports to connect to, etc.
- Synchronized Restart/Reset cannot be done
We will address some of these issues using Chained Configurations
. The theory is as follows. You will need a primary
configuration (launch or attach type) that will start the GDB Server (OpenOCD, STLink-GdbServer, pyocd, JLinkGDBServer, etc.). The first instance in most cases (except JLink) creates TCP ports for multiple debuggers (gdb) to connect to; one for each processor core. In the case of JLink, one server is launched for each processor core. The primary
configuration can optionally launch additional configurations. In launch.json, it can look something like
// What follows is a proposal. Not the FINAL incarnation
"numberOfProcessors": 3,
"targetProcessor": 1,
"chainedConfigurations": {
"enabled": true,
"waitOnEvent": "postInit",
"lifecycleManagedByParent": true,
"launches": [ // Array of launches. Order is respected
{
"name": "Attach Network Core", // Name of another configuration
"folder": "${workspaceRoot}/../net"
}
]
}
Most of the properties are available at the top level and for each launch. When specified at the top level, they are inherited by all the launches and each launch item can override the group. There is nothing stops a child configuration from having its own chained configurations. Hence the term chained
.
Configurations are organized as a tree with the primary
configuration at the root. They are typically related in some way. The child launches do not even have to be cortex-debug
configurations. Thay can be any valid configuration specified in launch.json
Name | Type | Description |
---|---|---|
enabled | boolean | At the top level, disables all chained configurations. You can enable at the top level but disable it for a chained launch individually |
waitOnEvent | enum | ["postInit" (default), "postStart"]. "postStart" means launch the configuration after the gdb-server has started and is ready for gdb connections. "portInit" means wait until all initialization commands have been completed -- generally, this also includes programming the device for one or more cores. "postInit" is a better option in most cases. With "postInit", (normally) the firmware is at the reset-handler and before even a single instruction is executed unless something is done in the "pre...", "override...", "post..." properties by your configuration. Note that "postInit" happens before "postStartSession" commands. "waitOnEvent" can be different for launches. |
name | string | Exact name of the launch configuration. See folder below. |
folder | string | Default: "". If not specified or an empty string, it means the current folder but it can be another folder in the workspace. You can either use the full-path name or the simple base-name of the folder as it appears in the .code-workspace file. Case matters. |
delayMs | number | Number of milliseconds to wait to launch this configuration. There is naturally a 5-millisecond delay between launches but you can add to that. The delays are additive in the chain. |
detached | boolean | If 'true' means that the chained launch configuration will have its own server and not shared with the parent. This is typical for 'JLink' gdbservers. For servers like OpenOCD, pyOCD, STLink-GdbServer, this should be false especially for multi-core devices. Unless specified, this is automatically done for you. |
lifecycleManagedByParent | boolean | See Life cycle management section below. |
launches | array | Array of launch objects where each launch object describes a chained launch. Applies to top-level only. |
This affects actions like Restart
, Reset
, Stop
, and Disconnect
. While we decide what to do as we don't yet know what is even possible in VSCode, you can submit your suggestions at https://github.com/Marus/cortex-debug/issues/547
ALl chained launch configurations are maintained as a tree that represents who launched what. This can be visualized in the Stack
window.
Note: This is a difficult topic We are not sure there is ONE right way of doing this. So, each node in the tree can have its own setting for lifecycleManagedByParent
. Even when certain nodes are detached, there is still only one root internally which is the primary launch configuration. Hopefully, what we got works for your situation.
When lifecycleManagedByParent
is false, each item in the launch tree is independently controlled. There are still things that can affect the entire launch tree. When you Stop
or Disconnect
the (primary) configuration that launched the server, the server is killed (by us). So, if there are any children still alive, they will die as well (eventually) as they will lose their connection to the HW. Normally, it is okay to Stop
or Detach
a dependent configuration and the others will keep running.
This is mostly managed by VSCode itself. Please remember that VSCode controls what happens when VSCode native buttons, commands, and keyboard shortcuts are invoked. When this is true, such global commands are directed to the root of the tree by VSCode automatically and then disseminated to each of the participating children in a top-down fashion. For Reset
and Restart
you must have proper customizations in your launch.json to make them do the right/expected thing. The defaults may not work.
There are two terms of importance:
-
Stop
: For native programs, this means killing the program. For us, it means to terminate the debug session, leave the target in an arbitrary state (depends on your gdb-server), generally halted. -
Disconnect
: It means to leave the program running. Not every gdb-server does this right. They may do the same thing asStop
or worse. Note that in the non-Windows/gdb world, this is calledDetach
. It is the opposite ofattach
.
Usually, there is not a problem with terminating a child (leaf) session where the child either disconnects or stops it is all good. But when a parent is asked to end a session, the parent (root) has to send a request to all its lifecycle-dependent children to terminate. Children are independent of each other running in different processes and VSCode coordinates some of that. The only API we have is to also ask the child to terminate but API cannot specify which method (Stop
or Disconnect
). This may change in the future as we will make that request with Microsoft. Note to self: But the question is what do we want?
These are NOT considered global events/actions. You can use the Cross Trigger Interface/Matrix
(CTI/CTM) to configure a synchronized halt.
-
Variables, Watch, and Stack windows should work normally and as expected. In the Stack Window though there will be one top-level item per configuration. The child configurations will be nested from its parent. We are still experimenting with this and are not sure what is possible with VSCode yet. This is something we have minimal control over.
-
DebugConsole: There will be one "Debug Console" for each session. In the "Debug Console", there is a drop-down list of sessions.
-
gdb-server: There will be one tab per gdb-server launched in the chain. This is also true for multi-session cases where each session that launched a gdb-server has a console. We cannot have one tab per child when the server is shared. This affects things like semi-hosting which can be confusing in a multi-core environment
-
Registers: You can only see the registers from the last breakpoint or pause. We know this is wrong and Registers should be shown on a per-thread-per-process basis.
-
Peripherals: There will only be one Peripheral Window. It is possible to add multiple SVD files (one for each session) in a tree. We have not decided on implementation yet. In most cases, users will have only one SVD file for the entire device and this will continue to work.
-
**RTT & SWO **: It is unclear how this will work. RTT should work normally with both OpenOCD and JLink. Technically, so will SWO. Please try to keep SWO usage to one configuration (doesn't have to be the
primary
root configuration)
While some gdb-servers are shared and others are separate, we have chosen a design to use separate GDB instances for each session. While it may be possible to use one GDB instance to debug multiple targets, it is confusing and hard to manage. This design aspect is unlikely to change.