summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthieu Longo <matthieu.longo@arm.com>2026-05-29 16:31:28 +0100
committerMatthieu Longo <matthieu.longo@arm.com>2026-08-17 22:34:56 +0100
commit9c99987237dcaca0c6c493d6a5fb0ab4dc7488e7 (patch)
tree80fd772ecd8dc059be6763f1a7f6ac918d6e9ab0
parentadd_archive_element(): Record pointer to my_archive for later use in the func... (diff)
gdb: align siginfo_t with the Linux kernel definitionHEADmaster
GDB's current definition of siginfo_t is missing many fields present in the Linux kernel definition [1]. These fields are useful for providing detailed, user-friendly diagnostics when a fault occurs. Some new AArch64 extensions, such as Permission Overlay Enhancement used to implement Protection Keys [2], require the debugger to inspect 'si_pkey' alongside 'si_addr' to help the user identify the problematic key. This patch aligns GDB's definition of the __sifields._sigfault member of siginfo_t with the definition from the Linux kernel master branch. To avoid hardcoding the field access paths throughout the codebase, this patch also introduces compile-time accessors for the siginfo_t attributes, centralizing their definitions in a single location and making future updates easier. Finally, extend the testsuite to verify access to the new si_pkey field and its preservation when modifying $_siginfo and when reading core files. The tests in siginfo-obj.exp rely on the siginfo_t definition provided by glibc's <signal.h>, which does not yet expose all of the fields present in the kernel definition. As a result, the tests cannot exercise every newly added field and therefore focus on si_pkey, the field motivating this change. The test validates that GDB can read and modify the field correctly; it does not attempt to generate a real protection-key fault. [1]: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/ tree/include/uapi/asm-generic/siginfo.h#n69 [2]: https://lore.kernel.org/all/20160212210213.ABC488FA@viggo.jf.intel.com/ Reviewed-By: Thiago Jung Bauermann <thiago.bauermann@linaro.org> Approved-By: Simon Marchi <simon.marchi@efficios.com>
-rw-r--r--gdb/aarch64-linux-tdep.c8
-rw-r--r--gdb/linux-tdep.c51
-rw-r--r--gdb/linux-tdep.h60
-rw-r--r--gdb/sparc64-linux-tdep.c6
-rw-r--r--gdb/testsuite/gdb.base/siginfo-obj.c1
-rw-r--r--gdb/testsuite/gdb.base/siginfo-obj.exp14
6 files changed, 130 insertions, 10 deletions
diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c
index f11eccc1bc1..235b35bcfb4 100644
--- a/gdb/aarch64-linux-tdep.c
+++ b/gdb/aarch64-linux-tdep.c
@@ -2683,13 +2683,15 @@ aarch64_linux_report_signal_info (struct gdbarch *gdbarch,
2683 2683
2684 try 2684 try
2685 { 2685 {
2686 using gdb_si = gdb::siginfo_type;
2687 using si_key = gdb::siginfo_type::key;
2686 /* Sigcode tells us if the segfault is actually a memory tag 2688 /* Sigcode tells us if the segfault is actually a memory tag
2687 violation. */ 2689 violation. */
2688 si_code = parse_and_eval_long ("$_siginfo.si_code"); 2690 si_code = parse_and_eval_long (gdb_si::get (si_key::siginfo_code));
2689 si_errno = parse_and_eval_long ("$_siginfo.si_errno"); 2691 si_errno = parse_and_eval_long (gdb_si::get (si_key::siginfo_errno));
2690 2692
2691 fault_addr 2693 fault_addr
2692 = parse_and_eval_long ("$_siginfo._sifields._sigfault.si_addr"); 2694 = parse_and_eval_long (gdb_si::get (si_key::siginfo_addr));
2693 } 2695 }
2694 catch (const gdb_exception_error &exception) 2696 catch (const gdb_exception_error &exception)
2695 { 2697 {
diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c
index 23e43ba5c5f..bbc4009d43c 100644
--- a/gdb/linux-tdep.c
+++ b/gdb/linux-tdep.c
@@ -272,10 +272,9 @@ static struct type *
272linux_get_siginfo_type (struct gdbarch *gdbarch) 272linux_get_siginfo_type (struct gdbarch *gdbarch)
273{ 273{
274 struct linux_gdbarch_data *linux_gdbarch_data; 274 struct linux_gdbarch_data *linux_gdbarch_data;
275 struct type *void_ptr_type;
276 struct type *uid_type, *pid_type; 275 struct type *uid_type, *pid_type;
277 struct type *sigval_type, *clock_type; 276 struct type *sigval_type, *clock_type;
278 struct type *siginfo_type, *sifields_type; 277 struct type *siginfo_type, *sifields_type, *sigfault_union_type;
279 struct type *type; 278 struct type *type;
280 279
281 linux_gdbarch_data = get_linux_gdbarch_data (gdbarch); 280 linux_gdbarch_data = get_linux_gdbarch_data (gdbarch);
@@ -285,11 +284,22 @@ linux_get_siginfo_type (struct gdbarch *gdbarch)
285 type_allocator alloc (gdbarch); 284 type_allocator alloc (gdbarch);
286 285
287 const struct builtin_type *builtin_types = builtin_type (gdbarch); 286 const struct builtin_type *builtin_types = builtin_type (gdbarch);
287 struct type *short_type = builtin_types->builtin_short;
288 struct type *int_type = builtin_types->builtin_int; 288 struct type *int_type = builtin_types->builtin_int;
289 struct type *uint_type = builtin_types->builtin_unsigned_int; 289 struct type *uint_type = builtin_types->builtin_unsigned_int;
290 struct type *long_type = builtin_types->builtin_long; 290 struct type *long_type = builtin_types->builtin_long;
291 291 struct type *unsigned_long_type = builtin_types->builtin_unsigned_long;
292 void_ptr_type = lookup_pointer_type (builtin_type (gdbarch)->builtin_void); 292 struct type *uint32_type = builtin_types->builtin_uint32;
293 struct type *void_ptr_type
294 = lookup_pointer_type (builtin_type (gdbarch)->builtin_void);
295
296 /* Compute padding length, i.e. __ADDR_BND_PKEY_PAD. */
297 unsigned alignof_void_ptr = type_align (void_ptr_type);
298 unsigned padding_size = (alignof_void_ptr < short_type->length ()
299 ? short_type->length ()
300 : alignof_void_ptr);
301 struct type *addr_bnd_pkey_padding_type
302 = init_vector_type (builtin_types->builtin_uint8, padding_size);
293 303
294 /* sival_t */ 304 /* sival_t */
295 sigval_type = arch_composite_type (gdbarch, NULL, TYPE_CODE_UNION); 305 sigval_type = arch_composite_type (gdbarch, NULL, TYPE_CODE_UNION);
@@ -364,9 +374,40 @@ linux_get_siginfo_type (struct gdbarch *gdbarch)
364 append_composite_type_field (type, "si_stime", clock_type); 374 append_composite_type_field (type, "si_stime", clock_type);
365 append_composite_type_field (sifields_type, "_sigchld", type); 375 append_composite_type_field (sifields_type, "_sigchld", type);
366 376
367 /* _sigfault */ 377 /* Begin _sigfault's anonymous union. */
378 sigfault_union_type = arch_composite_type (gdbarch, NULL, TYPE_CODE_UNION);
379 /* used on alpha and sparc */
380 append_composite_type_field (sigfault_union_type, "si_trapno", int_type);
381 /* used when si_code is BUS_MCEERR_AR or BUS_MCEERR_AO. */
382 append_composite_type_field (sigfault_union_type, "si_addr_lsb", short_type);
383
384 /* used when si_code=SEGV_BNDERR */
385 type = arch_composite_type (gdbarch, NULL, TYPE_CODE_STRUCT);
386 append_composite_type_field (type, "_dummy_bnd", addr_bnd_pkey_padding_type);
387 append_composite_type_field (type, "si_lower", void_ptr_type);
388 append_composite_type_field (type, "si_upper", void_ptr_type);
389 append_composite_type_field (sigfault_union_type, "_addr_bnd", type);
390
391 /* used when si_code=SEGV_PKUERR */
392 type = arch_composite_type (gdbarch, NULL, TYPE_CODE_STRUCT);
393 append_composite_type_field (type, "_dummy_pkey", addr_bnd_pkey_padding_type);
394 append_composite_type_field (type, "si_pkey", uint32_type);
395 append_composite_type_field (sigfault_union_type, "_addr_pkey", type);
396
397 /* used when si_code=TRAP_PERF */
398 type = arch_composite_type (gdbarch, NULL, TYPE_CODE_STRUCT);
399 append_composite_type_field (type, "si_perf_data", unsigned_long_type);
400 append_composite_type_field (type, "si_perf_type", uint32_type);
401 append_composite_type_field (type, "si_perf_flags", uint32_type);
402 append_composite_type_field (sigfault_union_type, "_perf", type);
403
404 /* End _sigfault's anonymous union. */
405
406 /* _sigfault is set by SIGILL, SIGFPE, SIGSEGV, SIGBUS, SIGTRAP, SIGEMT */
368 type = arch_composite_type (gdbarch, NULL, TYPE_CODE_STRUCT); 407 type = arch_composite_type (gdbarch, NULL, TYPE_CODE_STRUCT);
369 append_composite_type_field (type, "si_addr", void_ptr_type); 408 append_composite_type_field (type, "si_addr", void_ptr_type);
409 /* Note: this is an anonymous union. */
410 append_composite_type_field (type, "", sigfault_union_type);
370 append_composite_type_field (sifields_type, "_sigfault", type); 411 append_composite_type_field (sifields_type, "_sigfault", type);
371 412
372 /* _sigpoll */ 413 /* _sigpoll */
diff --git a/gdb/linux-tdep.h b/gdb/linux-tdep.h
index c19839fde2c..1f40756eb2f 100644
--- a/gdb/linux-tdep.h
+++ b/gdb/linux-tdep.h
@@ -98,4 +98,64 @@ extern CORE_ADDR linux_get_hwcap2 ();
98extern bool linux_address_in_shadow_stack_mem_range 98extern bool linux_address_in_shadow_stack_mem_range
99 (CORE_ADDR addr, std::pair<CORE_ADDR, CORE_ADDR> *range); 99 (CORE_ADDR addr, std::pair<CORE_ADDR, CORE_ADDR> *range);
100 100
101namespace gdb {
102
103/* Maps each siginfo_type::key to the corresponding field-access expression
104 in $_siginfo.
105
106 Keep the order of key values synchronized with the entries in get()'s
107 paths array. Each key is used directly as an array index. */
108
109struct siginfo_type
110{
111 /* Identifies a field within siginfo_t that may be referenced by name. */
112 enum class key
113 {
114 siginfo_signo = 0,
115 siginfo_errno,
116 siginfo_code,
117
118 /* SIGILL, SIGFPE, SIGSEGV, SIGBUS, SIGTRAP, SIGEMT */
119 siginfo_addr,
120 siginfo_trapno,
121 siginfo_addr_lsb,
122 siginfo_lower,
123 siginfo_upper,
124 siginfo_pkey,
125 siginfo_perf_data,
126 siginfo_perf_type,
127 siginfo_perf_flags,
128
129 /* Sentinel used to determine the number of mapped fields. */
130 SIGINFO_ATTR_END
131 };
132
133 /* Return the $_siginfo access expression associated with ATTR_.
134
135 ATTR_ must be a valid si_* key other than SIGINFO_ATTR_END. The array
136 order must exactly match the declaration order of the keys above. */
137 static constexpr const char *get (key attr_)
138 {
139 const char *paths[static_cast<size_t> (key::SIGINFO_ATTR_END)] = {
140 "$_siginfo.si_signo",
141 "$_siginfo.si_errno",
142 "$_siginfo.si_code",
143
144 /* SIGILL, SIGFPE, SIGSEGV, SIGBUS, SIGTRAP, SIGEMT */
145 "$_siginfo._sifields._sigfault.si_addr",
146 "$_siginfo._sifields._sigfault.si_trapno",
147 "$_siginfo._sifields._sigfault.si_addr_lsb",
148 "$_siginfo._sifields._sigfault._addr_bnd.si_lower",
149 "$_siginfo._sifields._sigfault._addr_bnd.si_upper",
150 "$_siginfo._sifields._sigfault._addr_pkey.si_pkey",
151 "$_siginfo._sifields._sigfault._perf.si_perf_data",
152 "$_siginfo._sifields._sigfault._perf.si_perf_type",
153 "$_siginfo._sifields._sigfault._perf.si_perf_flags",
154 };
155 return paths[static_cast<size_t> (attr_)];
156 }
157};
158
159} /* namespace gdb */
160
101#endif /* GDB_LINUX_TDEP_H */ 161#endif /* GDB_LINUX_TDEP_H */
diff --git a/gdb/sparc64-linux-tdep.c b/gdb/sparc64-linux-tdep.c
index cb7ce41e5cb..b6245f64bae 100644
--- a/gdb/sparc64-linux-tdep.c
+++ b/gdb/sparc64-linux-tdep.c
@@ -134,11 +134,13 @@ sparc64_linux_report_signal_info (struct gdbarch *gdbarch, struct ui_out *uiout,
134 134
135 try 135 try
136 { 136 {
137 using gdb_si = gdb::siginfo_type;
138 using si_key = gdb::siginfo_type::key;
137 /* Evaluate si_code to see if the segfault is ADI related. */ 139 /* Evaluate si_code to see if the segfault is ADI related. */
138 si_code = parse_and_eval_long ("$_siginfo.si_code\n"); 140 si_code = parse_and_eval_long (gdb_si::get (si_key::siginfo_code));
139 141
140 if (si_code >= SEGV_ACCADI && si_code <= SEGV_ADIPERR) 142 if (si_code >= SEGV_ACCADI && si_code <= SEGV_ADIPERR)
141 addr = parse_and_eval_long ("$_siginfo._sifields._sigfault.si_addr"); 143 addr = parse_and_eval_long (gdb_si::get (si_key::siginfo_addr));
142 } 144 }
143 catch (const gdb_exception_error &exception) 145 catch (const gdb_exception_error &exception)
144 { 146 {
diff --git a/gdb/testsuite/gdb.base/siginfo-obj.c b/gdb/testsuite/gdb.base/siginfo-obj.c
index 43dc979bc50..960e5b8e9cd 100644
--- a/gdb/testsuite/gdb.base/siginfo-obj.c
+++ b/gdb/testsuite/gdb.base/siginfo-obj.c
@@ -35,6 +35,7 @@ handler (int sig, siginfo_t *info, void *context)
35 int ssi_signo = info->si_signo; 35 int ssi_signo = info->si_signo;
36 int ssi_code = info->si_code; 36 int ssi_code = info->si_code;
37 void *ssi_addr = info->si_addr; 37 void *ssi_addr = info->si_addr;
38 unsigned int ssi_pkey = info->si_pkey;
38 39
39 _exit (0); /* set breakpoint here */ 40 _exit (0); /* set breakpoint here */
40} 41}
diff --git a/gdb/testsuite/gdb.base/siginfo-obj.exp b/gdb/testsuite/gdb.base/siginfo-obj.exp
index a94bf0e33ba..a724a634dc0 100644
--- a/gdb/testsuite/gdb.base/siginfo-obj.exp
+++ b/gdb/testsuite/gdb.base/siginfo-obj.exp
@@ -78,6 +78,14 @@ gdb_test_multiple "p \$_siginfo" "$test" {
78 } 78 }
79} 79}
80 80
81set test "extract si_pkey"
82gdb_test_multiple "p \$_siginfo" "$test" {
83 -re "si_pkey = (\[0-9\]\+).*$gdb_prompt $" {
84 set ssi_pkey $expect_out(1,string)
85 pass "$test"
86 }
87}
88
81set bp_location [gdb_get_line_number "set breakpoint here"] 89set bp_location [gdb_get_line_number "set breakpoint here"]
82 90
83with_test_prefix "validate siginfo fields" { 91with_test_prefix "validate siginfo fields" {
@@ -87,6 +95,7 @@ with_test_prefix "validate siginfo fields" {
87 gdb_test "p ssi_errno" " = $ssi_errno" 95 gdb_test "p ssi_errno" " = $ssi_errno"
88 gdb_test "p ssi_code" " = $ssi_code" 96 gdb_test "p ssi_code" " = $ssi_code"
89 gdb_test "p ssi_signo" " = $ssi_signo" 97 gdb_test "p ssi_signo" " = $ssi_signo"
98 gdb_test "p ssi_pkey" " = $ssi_pkey"
90} 99}
91 100
92# Again, but this time, patch si_addr and check that the inferior sees 101# Again, but this time, patch si_addr and check that the inferior sees
@@ -106,6 +115,7 @@ gdb_test "p \$_siginfo._sifields._sigfault.si_addr = 0x666" " = \\(void \\*\\) 0
106gdb_test "p \$_siginfo.si_errno = 666" " = 666" 115gdb_test "p \$_siginfo.si_errno = 666" " = 666"
107gdb_test "p \$_siginfo.si_code = 999" " = 999" 116gdb_test "p \$_siginfo.si_code = 999" " = 999"
108gdb_test "p \$_siginfo.si_signo = 11" " = 11" 117gdb_test "p \$_siginfo.si_signo = 11" " = 11"
118gdb_test "p \$_siginfo._sifields._sigfault._addr_pkey.si_pkey = 123" " = 123"
109 119
110with_test_prefix "validate modified siginfo fields" { 120with_test_prefix "validate modified siginfo fields" {
111 gdb_test "break $bp_location" 121 gdb_test "break $bp_location"
@@ -114,6 +124,7 @@ with_test_prefix "validate modified siginfo fields" {
114 gdb_test "p ssi_errno" " = 666" 124 gdb_test "p ssi_errno" " = 666"
115 gdb_test "p ssi_code" " = 999" 125 gdb_test "p ssi_code" " = 999"
116 gdb_test "p ssi_signo" " = 11" 126 gdb_test "p ssi_signo" " = 11"
127 gdb_test "p ssi_pkey" " = 123"
117} 128}
118 129
119# Test siginfo preservation in core files. 130# Test siginfo preservation in core files.
@@ -132,4 +143,7 @@ if {$gcore_created} {
132 gdb_test "p \$_siginfo._sifields._sigfault.si_addr" \ 143 gdb_test "p \$_siginfo._sifields._sigfault.si_addr" \
133 " = \\(void \\*\\) $ssi_addr" \ 144 " = \\(void \\*\\) $ssi_addr" \
134 "p \$_siginfo._sifields._sigfault.si_addr from core file" 145 "p \$_siginfo._sifields._sigfault.si_addr from core file"
146 gdb_test "p \$_siginfo._sifields._sigfault._addr_pkey.si_pkey" \
147 " = $ssi_pkey" \
148 "p \$_siginfo._sifields._sigfault._addr_pkey.si_pkey from core file"
135} 149}