forked from oxidecomputer/humility
-
Notifications
You must be signed in to change notification settings - Fork 0
/
README.md.in
272 lines (210 loc) · 11 KB
/
README.md.in
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
# Humility
Humility is the debugger for
<a href="https://github.com/oxidecomputer/hubris">Hubris</a>.
## Installation
### Runtime dependencies
You may want any of the following dependencies depending on how you run hubris. This can be installed however you like, but some options will be outlined in the following sections.
- gdb (this must have multi architecture support)
- openocd
- qemu (must include your desired architectures). Be aware that `riscv` targets require semihosting support which is not yet in release, but will land in v7.2.0 and is in the master branch.
### Nix
#### System Requirements
[nix: the package manager](https://nixos.org/download.html)
#### Installation
`nix profile install 'github:rivosinc/humility'`
This will install the latest master branch (see [Avoid building from source](#avoid-building-from-source)).
#### Runtime Dependencies
If you would like to also install the runtime dependencies also run:
- `nix profile install nixpkgs#gdb`
- `nix profile install nixpkgs#openocd`
- `nix profile install nixpkgs#qemu` or `nix profile install github:rivosinc/qemu/dev/drew/nix` if you need semihosting
This will install multi architecture versions to your system (they will be accesible outside of humility).
#### Avoid building from source
By default nix will build humility from source. We can add the binary cache to avoid this. Run this before installing humility from nix:
`nix profile install nixpkgs#cachix && cachix use hubris-humility`
### DIY (from source)
#### System Requirements
To successfully build and install humility from source you need:
- [rustup](https://rustup.rs/)*
- cargo-readme (`cargo install cargo-readme`)
- libusb1 (installation depends on your platform)
\* A word of warning: the system installed version of rust may or may not cause problems and may or may not need to be uninstalled...
#### Installation
`cargo install --git https://github.com/rivosinc/humility.git --locked humility`
or
`git clone https://github.com/rivosinc/humility.git && cargo install --locked --path ./humility`
These both build from source.
#### Dependencies
On ubuntu:
- `sudo apt install gdb-multiarch`
- `sudo apt install openocd`
- `sudo apt install qemu-system-arm`, adjust for your target platform (There is no riscv qemu in apt right now)
## Guiding principles
### Production disposition
Hubris is the artifact that actually runs, and it must be allowed to be
optimized in terms of size, space, and run-time; in as much as contortions are
required for debuggability, they should be borne by Humility, not Hubris. As a
concrete example of this, Humility operates exclusively on `release` builds of
Hubris, relying on (unloaded) DWARF information in the binaries to make sense of
the system.
### Hubris-specific
Humility is Hubris-specific: it is not trying to be a generic *in situ*
debugger, but rather specifically focused on debugging Hubris-based systems.
Humility is therefore willing to encode Hubris-specific concepts like
archives and tasks.
### Microcontroller-specific
Debuggers must cut through abstractions, which
often requires knowledge of underlying
implementation detail. For Humility, this means being willing to take
advantage of microcontroller-specific debug facilities where applicable.
While Hubris may make decisions in the name of greater portability,
Humility will generally make decisions to maximize debuggability, even
where these facilities are highly specific to a particular MCU.
### Device-specific
Humility is unafraid to offer device-specific functionality where that
functionality is useful for system debuggability. (For example,
`humility i2c` functions as an I<sup>2</sup>C analyzer.) That said, all device
interaction uses Hubris as a proxy to actually communicate with the devices
themselves (e.g., via [HIF](https://github.com/oxidecomputer/hif));
Humility does not seek to create second I/O path.
### Pragmatic
Humility seeks to be *useful*, and therefore seeks to offer all manners of
debugging: in situ, postmortem, dynamic instrumentation, static
instrumentation, etc.
## Operation
Humility operates by specifying a subcommand. There are options that
are Humility-wide (that is, applying to every subcommand), as well as
options that are specific to particular subcommands.
### Probe
Humility needs to have some way of extracting information and/or controlling
the microcontroller running Hubris. This is done through some variant of a
debug *probe*, a separate microcontroller that speaks to debug-specific
functionality on the target microcontroller. (For details of the mechanics
of these probes on ARM parts, see <a
href="https://65.rfd.oxide.computer">RFD 65</a>.)
For most evaluation boards, this debug probe is available on the board, and
is connected to a host via USB, e.g. ST's STLink/V2 on the STM32F407
Discovery or the LPC-Link2 present on the LPCXpresso55S69.
(On the Gemini board, there are two SWD headers, one for the LPC55S28
and the other for the STM32H753.)
While Humility allows for direct attachment to an on-chip debugger, doing so
precludes other connections (from, for example, OpenOCD), making it too
disruptive to development workflows. To allow for easier development
workflows, Humility also has the option to attach via OpenOCD.
The debug probe to use is specified to Humility via the `-p` option
(long form `--probe`) or the `HUMILITY_PROBE` environment variable,
which can have the following values:
- `auto` (default): Automatically determine how to attach to the
microcontroller.
- `ocd`: Attach via OpenOCD, which is presumed to have the TCL interface
available on localhost on port 6666 (its default).
- `jlink`: Attach via Segger JLink, which is presumed to have the GDB
interface available on localhost on port 2331 (its default). Note that
when semihosting is being used by Hubris, the Segger JLink GDB server
will become confused when Humility attaches to it -- and subsequent
calls to semihosting will cause a halt. A subsequent Humility invocation
will resume the target (directing semihosting output correctly to the
running GDB instance), but subsequent semihosting output will again cause
a halt. To recover from this condition, send an explicit ^C to the
running GDB and continue from the resulting stop.
- `qemu`: Attach via Qemu's GDB server, which is presumed to have the interface
available on localhost:3333. Currently, reading registers does NOT work.
- `usb`: Attach directly via USB to a debug probe. When multiple probes
are plugged in via USB, a probe index must be specified as a suffix
(e.g., `usb-0`, `usb-1`, etc.) To determine which probe is which,
examine the serial number in the output of `humility probe`.
- `vid:pid[:serial]`: In some cases, the automatic algorithm may either find
the wrong thing, or timeout attempting to search for non-existent probes.
In these cases, it can help to explicitly set the vendor ID (VID) and
product ID (PID) of the debug probe, which should be colon-delimited, e.g.,
`0483:374e`. (Determining the VID and PID of an attached probe is
platform-specific; on Linux one can use the `lsusb` command.) In cases
where there are multiple probes with the same VID and PID, the serial number
of the probe (as reported via `humility probe` or found in the
`iSerialNumber` field of the USB device descriptor) can be postpended,
also delimited by a colon, e.g. `0483:374e:004000343137510939383538`.
### Archive
Many Humility commands require the complete Hubris archive. This is a ZIP
archive created by the build process, and includes all binaries as well as the
`app.toml` file used to configure the Hubris archive. The archive can be
found in the `target` for Hubris, and will end with (`.zip`), e.g.:
`/path/to/hubris/target/demo-stm32h743-nucleo/dist/build-demo-stm32h743-nucleo.zip`.
The Hubris archive is specified via the `-a` option or the `HUMILITY_ARCHIVE`
environment variable.
**In the Humility examples in this documentation, unless otherwise specified,
the archive will be assumed to be set via `-a` or `HUMILITY_ARCHIVE`.**
### Dump
Many Humility commands are able to operate *postmortem* on a Hubris dump,
an ELF core file generated by the `humility dump` command.
Dumps are offered in lieu of a probe and an archive and specified via
the `-d` option (long form `--dump`) or the `HUMILITY_DUMP` environment
variable.
### Environment
On machines that have several different connected Hubris targets, Humility can
become thorny to manage. To aid this, Humility allows for *environments*:
JSON files that define how targets can be reached and auxiliary operations
that can be performed upon them. The environment file is specified via either
the `--environment` argument or via the `HUMILITY_ENVIRONMENT` environment
variable; a specific target within the environment is specified via the
`--target` argument or via the `HUMILITY_TARGET` environment variable.
#### Environment file structure
The environment file contains a JSON object in which each key represents a
target. The members of each target object must include `probe` and `archive`,
which have the same meaning as the probe and archive as provided via the
command line. For example:
```json
{
"lucky": {
"probe": "0483:374e:002A00174741500520383733",
"archive": "/gimlet/hubris/archives/lucky/build-gimlet.zip"
},
"sweaty": {
"probe": "0483:374e:000D00184741500520383733",
"archive": "/gimlet/hubris/archives/sweaty/build-gimlet.zip"
},
"grimey": {
"probe": "0483:374e:003400185553500820393256",
"archive": "/gimlet/hubris/archives/grimey/build-gimlet.zip"
}
}
```
Some targets may require multiple archives. These can be specified by
name. The archive to be used must be specified with the `--archive-name`
option to humility.
```json
{
"lucky": {
"probe": "0483:374e:002A00174741500520383733",
"archive": {
imagea: "/gimlet/hubris/archives/lucky/build-a-gimlet.zip",
imageb: "/gimlet/hubris/archives/lucky/build-b-gimlet.zip"
}
},
}
```
The above definition -- when provided via `--environment` or
`HUMILITY_ENVIRONMENT` -- would allow one to (say) run `humility --target
grimey tasks` or `humility --target lucky --image-name imagea tasks`.
In addition to `probe` and `archive`, one may also specify
associated commands in a `cmds` object that contains a mapping of names to
commands to execute. For example:
```json
{
"grimey": {
"probe": "0483:374e:003400185553500820393256",
"archive": "/gimlet/hubris/archives/grimey/build-gimlet.zip"
"cmds": {
"console": "/bin/sh -c \"grabserial.sh $(findtty.sh grimey)\"",
"power": {
"on": "power.sh --on grimey",
"off": "power.sh --off grimey",
"status": "power.sh --status grimey",
}
}
}
}
```
These commands can be in principle accessed by any debugging command, but the
`humility exec` command in particular allows one to execute a command against
a specified target. (In the above example, one could execute `humility
--target grimey exec power.on`.)