Skip to content

Commit 15860bb

Browse files
authored
feat(crashtracking)!: emit ucontext registers as structured data (#1787)
# What does this PR do? This PR extracts out register data from `ucontext` and emits ucontext as structured data. The reason we do this is because ucontext register and pointer values are needed as structured data for downstream diagnosis workflows. We also promote ucontext from an experimental field to a field in the top level report # Motivation [RFC: Crashtracker Crash Pre-Diagnosis](https://docs.google.com/document/d/18ufgwT1WK6YKCpz_N_u59MLMyRB-ot-7vbuOJ77xPK0/edit?usp=sharing) # Additional Notes Schema ``` { "$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "title": "UContext Schema", "description": "JSON schema for crashtracker ucontext data", "required": ["arch", "registers", "raw"], "properties": { "arch": { "type": "string", "enum": ["x86_64", "aarch64"], "description": "Target architecture" }, "registers": { "type": "object", "description": "CPU register values as key-value pairs with hex string values", "additionalProperties": { "type": "string", "pattern": "^0x[0-9a-f]+$" } }, "raw": { "type": "string", "description": "Debug representation of the complete ucontext structure" } }, "additionalProperties": false } ``` Example payload ``` { "arch": "x86_64", "registers": { "rax": "0x00007ffceae07410", "rdx": "0x00007ffceae07418", "r8": "0x000055fcfd2ec010", "r11": "0x346a1a95dc671c71", "rsp": "0x00007ffceae033f8", "rdi": "0x00000000000003fc", "rbx": "0x00000000000003fc", "r12": "0x000055fcce53ad28", "r10": "0x000055fcfd2ecf80", "r13": "0x000000000000001a", "rip": "0x000055fcce4d7d90", "rsi": "0x00000000000003fb", "rbp": "0x0000000000000001", "r9": "0x0000000000000007", "rcx": "0x0000000000000000", "r14": "0x00007ffceae07418", "r15": "0x0000000000000000" }, "raw": "ucontext_t { uc_flags: 7, uc_link: 0x0, uc_stack: stack_t { ss_sp: 0x7f70abd74000, ss_flags: 0, ss_size: 65536 }, uc_mcontext: mcontext_t { gregs: [94545067819024, 7, 94545067822976, 3776860468453776497, 94544281709864, 26, 140724249064472, 0, 1020, 1019, 1, 1020, 140724249064472, 140724249064464, 0, 140724249048056, 94544281304464, 66050, 12103423998558259, 6, 14, 0, 140724249048056], fpregs: 0x7f70abd83c80, __private: [0, 0, 0, 0, 0, 0, 0, 0] }, uc_sigmask: sigset_t { __val: [0, 11, 1, 140724249048056, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }, __private: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 31, 0, 0, 255, 255, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 240, 238, 223, 235, 252, 127, 0, 0, 104, 167, 83, 206, 252, 85, 0, 0, 192, 58, 192, 171, 112, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 112, 123, 47, 253, 252, 85, 0, 0, 160, 123, 47, 253, 252, 85, 0, 0, 222, 196, 170, 171, 112, 127, 0, 0, 48, 239, 223, 235, 252, 127, 0, 0, 97, 5, 177, 171, 112, 127, 0, 0, 48, 241, 223, 235, 252, 127, 0, 0, 32, 0, 0, 96, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 21, 227, 170, 171, 112, 127, 0, 0, 104, 167, 83, 206, 252, 85, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 240, 105, 47, 253, 252, 85, 0, 0, 255, 0, 0, 255, 0, 0, 255, 255, 255, 0, 255, 0, 255, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 0, 0, 0, 255, 0, 0, 0, 0, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 83, 88, 80, 70, 68, 3, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 64, 3, 0, 0, 0, 0, 0, 0], __ssp: [0, 0, 0, 3] }" } ``` # How to test the change? Unit test Co-authored-by: gyuheon.oh <[email protected]>
1 parent 29678bd commit 15860bb

10 files changed

Lines changed: 451 additions & 46 deletions

File tree

docs/RFCs/0011-crashtracker-structured-log-format-V1_X.md

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "S
44

55
## Summary
66

7-
This document consolidates and describes the complete evolution of the crashinfo data format from version 1.0 through 1.4. It serves as the authoritative specification for the crashtracker structured log format, replacing RFCs 0005-0009. Future minor version modifications will be included in this revisable document.
7+
This document consolidates and describes the complete evolution of the crashinfo data format from version 1.0 through 1.6. It serves as the authoritative specification for the crashtracker structured log format, replacing RFCs 0005-0009. Future minor version modifications will be included in this revisable document.
88

99
## Motivation
1010

@@ -18,9 +18,9 @@ As a structured format, it avoids the ambiguity of standard semi-structured stac
1818
Due to the use of native extensions, it is possible for a single stack-trace to include frames from multiple languages (e.g. python may call C code, which calls Rust code, etc).
1919
Having a single structured format allows us to work across languages.
2020

21-
## Current Format (Version 1.4)
21+
## Current Format (Version 1.6)
2222

23-
This section describes the current format (version 1.4), which incorporates all features from versions 1.0 through 1.4. A natural language description of the json format is given here. An example is given in Appendix A, and the schema is given in Appendix B.
23+
This section describes the current format (version 1.6), which incorporates all features from versions 1.0 through 1.6. A natural language description of the json format is given here. An example is given in Appendix A, and the schema is given in Appendix B.
2424

2525
Any field not listed as "Required" is optional. Consumers MUST accept json with elided optional fields.
2626

@@ -32,20 +32,22 @@ Parsers SHOULD therefore accept unexpected fields, either by ignoring them, or b
3232

3333
### Version Compatibility
3434

35-
Consumers of the crash data format SHOULD be designed to handle all versions from 1.0 to 1.4. The version is indicated by the `data_schema_version` field. Key compatibility considerations:
35+
Consumers of the crash data format SHOULD be designed to handle all versions from 1.0 to 1.6. The version is indicated by the `data_schema_version` field. Key compatibility considerations:
3636
- Version 1.0: Base format
3737
- Version 1.1+: Stacktraces may include an `incomplete` field
3838
- Version 1.2+: Root level may include an `experimental` field
3939
- Version 1.3+: Stackframes may include a `comments` field
4040
- Version 1.4+: Stackframes may include a `mangled_name` field
41+
- Version 1.5+: Error objects may include a `thread_name` field
42+
- Version 1.6+: Root level may include a `ucontext` field for UNIX signal crashes
4143

4244
### Fields
4345

4446
- `counters`: **[optional]**
4547
A map of names to integer values.
4648
At present, this is used by the profiler to track which operations were active at the time of the crash.
4749
- `data_schema_version`: **[required]**
48-
A string containing the semver ID of the crashtracker data schema. Current versions: "1.0", "1.1", "1.2", "1.3", "1.4".
50+
A string containing the semver ID of the crashtracker data schema. Current versions: "1.0", "1.1", "1.2", "1.3", "1.4", "1.5", "1.6".
4951
- `experimental`: **[optional]** *[Added in v1.2]*
5052
Any valid JSON object can be used as the value here.
5153
Note that the object MUST be valid JSON.
@@ -132,6 +134,17 @@ Consumers of the crash data format SHOULD be designed to handle all versions fro
132134
- `si_signo_human_readable`: **[required]**
133135
The signal name, e.g. "SIGSEGV".
134136
Follows the naming convention in [the manpage](https://man7.org/linux/man-pages/man7/signal.7.html).
137+
- `ucontext`: **[optional]**
138+
UNIX signal based collectors only: CPU register state captured from the `ucontext_t` structure at the time of the crash signal.
139+
- `arch`: **[required]**
140+
Target architecture, e.g. "x86_64" or "aarch64".
141+
- `registers`: **[required]**
142+
A map of register names to their hexadecimal string values.
143+
Register names follow the platform conventions (e.g., "rip", "rsp", "rbp" for x86_64; "pc", "sp", "x0", "x1" for aarch64).
144+
Values are formatted as zero-padded 16-character hexadecimal strings, e.g. "0x00007f7e11d3a2b0".
145+
- `raw`: **[optional]**
146+
The complete debug-formatted string representation of the ucontext structure.
147+
Preserves FPU state, signal mask, alternate-stack info, and other details not captured in the structured registers.
135148
- `span_ids`: **[optional]**
136149
A vector representing active span ids at the time of program crash.
137150
The collector MAY cap the number of spans that it tracks.
@@ -276,27 +289,37 @@ This section documents the evolution of the crashtracker structured log format a
276289
**Motivation:** When symbol names are demangled for readability, the original mangled names are lost. This makes debugging difficult when mangled names are needed (e.g., comparing against compiler-generated symbols). The `mangled_name` field preserves the original mangled name when demangling occurs.
277290

278291
### Version 1.5
279-
*Added thread_name to `ErrorData`
292+
*Added thread_name to `ErrorData`*
280293

281294
**Changes from v1.4:**
282295
- Added `thread_name` field to `Error` objects (optional string)
283296
- Updated `data_schema_version` to "1.5"
284297

285298
**Motivation:** Having access to thread name of the crashing thread helps debugging, especially within multithreaded programs.
286299

300+
### Version 1.6
301+
*Added ucontext field*
302+
303+
**Changes from v1.5:**
304+
- Added `ucontext` field at root level (optional object for UNIX signal crashes)
305+
- Updated `data_schema_version` to "1.6"
306+
307+
**Motivation:** CPU register state at the time of crash provides critical debugging information for low-level crashes. The ucontext structure captured by UNIX signal handlers contains register values, FPU state, signal masks, and alternate stack information that can help developers understand the exact processor state when the crash occurred.
308+
287309
## Appendix A: Example output
288310

289311
An example crash report in version 1.0 format is [available here](artifacts/0005-crashtracker-example.json).
290312

291-
Note: This example uses version 1.0 format. Version 1.1+ may include additional fields such as `incomplete` in stacktraces, `experimental` at the root level, `comments` in stackframes, and `mangled_name` in stackframes.
313+
Note: This example uses version 1.0 format. Version 1.1+ may include additional fields such as `incomplete` in stacktraces, `experimental` at the root level, `comments` in stackframes, `mangled_name` in stackframes, `thread_name` in error objects, and `ucontext` at the root level for UNIX signal crashes.
292314

293315
## Appendix B: Json Schema
294316

295-
The current JSON schema (version 1.5) is [available here](artifacts/crashtracker-unified-runtime-stack-schema-v1_5.json).
317+
The current JSON schema (version 1.6) is [available here](artifacts/crashtracker-unified-runtime-stack-schema-v1_6.json).
296318

297319
Historical schemas are also available:
298320
- [Version 1.0 schema](artifacts/0005-crashtracker-schema.json)
299321
- [Version 1.1 schema](artifacts/0006-crashtracker-schema.json)
300322
- [Version 1.2 schema](artifacts/0007-crashtracker-schema.json)
301323
- [Version 1.3 schema](artifacts/0008-crashtracker-schema.json)
302324
- [Version 1.4 schema](artifacts/0009-crashtracker-schema.json)
325+
- [Version 1.5 schema](artifacts/crashtracker-unified-runtime-stack-schema-v1_5.json)

docs/RFCs/artifacts/0011-crashtracker-unified-runtime-stack-schema.json renamed to docs/RFCs/artifacts/crashtracker-unified-runtime-stack-schema-v1_6.json

Lines changed: 52 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,16 @@
100100
"$ref": "#/definitions/Span"
101101
}
102102
},
103+
"ucontext": {
104+
"anyOf": [
105+
{
106+
"$ref": "#/definitions/Ucontext"
107+
},
108+
{
109+
"type": "null"
110+
}
111+
]
112+
},
103113
"uuid": {
104114
"type": "string"
105115
}
@@ -141,6 +151,12 @@
141151
"stack": {
142152
"$ref": "#/definitions/StackTrace"
143153
},
154+
"thread_name": {
155+
"type": [
156+
"string",
157+
"null"
158+
]
159+
},
144160
"threads": {
145161
"type": "array",
146162
"items": {
@@ -175,12 +191,6 @@
175191
"type": "null"
176192
}
177193
]
178-
},
179-
"ucontext": {
180-
"type": [
181-
"string",
182-
"null"
183-
]
184194
}
185195
}
186196
},
@@ -251,6 +261,14 @@
251261
"type": "integer",
252262
"format": "uint32",
253263
"minimum": 0.0
264+
},
265+
"tid": {
266+
"type": [
267+
"integer",
268+
"null"
269+
],
270+
"format": "uint32",
271+
"minimum": 0.0
254272
}
255273
}
256274
},
@@ -564,6 +582,34 @@
564582
]
565583
}
566584
}
585+
},
586+
"Ucontext": {
587+
"description": "Structured representation of the CPU register state captured from a `ucontext_t` at the time of a crash signal.",
588+
"type": "object",
589+
"required": [
590+
"arch",
591+
"registers"
592+
],
593+
"properties": {
594+
"arch": {
595+
"description": "Target architecture: \"x86_64\" or \"aarch64\"",
596+
"type": "string"
597+
},
598+
"raw": {
599+
"description": "Full Debug-formatted ucontext string preserving FPU state, signal mask, and alternate-stack info that is not captured in `registers`.",
600+
"type": [
601+
"string",
602+
"null"
603+
]
604+
},
605+
"registers": {
606+
"description": "Named registers mapped to their hex-formatted values (\"rip\" -> \"0x00007f...\")",
607+
"type": "object",
608+
"additionalProperties": {
609+
"type": "string"
610+
}
611+
}
612+
}
567613
}
568614
}
569615
}

0 commit comments

Comments
 (0)