Skip to content

Commit d28abd2

Browse files
rpedgecohansendc
authored andcommitted
x86: Separate out x86_regset for 32 and 64 bit
In fill_thread_core_info() the ptrace accessible registers are collected for a core file to be written out as notes. The note array is allocated from a size calculated by iterating the user regset view, and counting the regsets that have a non-zero core_note_type. However, this only allows for there to be non-zero core_note_type at the end of the regset view. If there are any in the middle, fill_thread_core_info() will overflow the note allocation, as it iterates over the size of the view and the allocation would be smaller than that. To apparently avoid this problem, x86_32_regsets and x86_64_regsets need to be constructed in a special way. They both draw their indices from a shared enum x86_regset, but 32 bit and 64 bit don't all support the same regsets and can be compiled in at the same time in the case of IA32_EMULATION. So this enum has to be laid out in a special way such that there are no gaps for both x86_32_regsets and x86_64_regsets. This involves ordering them just right by creating aliases for enum’s that are only in one view or the other, or creating multiple versions like REGSET32_IOPERM/REGSET64_IOPERM. So the collection of the registers tries to minimize the size of the allocation, but it doesn’t quite work. Then the x86 ptrace side works around it by constructing the enum just right to avoid a problem. In the end there is no functional problem, but it is somewhat strange and fragile. It could also be improved like this [1], by better utilizing the smaller array, but this still wastes space in the regset array’s if they are not carefully crafted to avoid gaps. Instead, just fully separate out the enums and give them separate 32 and 64 enum names. Add some bitsize-free defines for REGSET_GENERAL and REGSET_FP since they are the only two referred to in bitsize generic code. While introducing a bunch of new 32/64 enums, change the pattern of the name from REGSET_FOO32 to REGSET32_FOO to better indicate that the 32 is in reference to the CPU mode and not the register size, as suggested by Eric Biederman. This should have no functional change and is only changing how constants are generated and referred to. [1] https://lore.kernel.org/lkml/20180717162502.32274-1-yu-cheng.yu@intel.com/ Signed-off-by: Rick Edgecombe <rick.p.edgecombe@intel.com> Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com> Link: https://lore.kernel.org/all/20221021221803.10910-2-rick.p.edgecombe%40intel.com
1 parent c9053e1 commit d28abd2

1 file changed

Lines changed: 43 additions & 24 deletions

File tree

arch/x86/kernel/ptrace.c

Lines changed: 43 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -44,16 +44,35 @@
4444

4545
#include "tls.h"
4646

47-
enum x86_regset {
48-
REGSET_GENERAL,
49-
REGSET_FP,
50-
REGSET_XFP,
51-
REGSET_IOPERM64 = REGSET_XFP,
52-
REGSET_XSTATE,
53-
REGSET_TLS,
54-
REGSET_IOPERM32,
47+
enum x86_regset_32 {
48+
REGSET32_GENERAL,
49+
REGSET32_FP,
50+
REGSET32_XFP,
51+
REGSET32_XSTATE,
52+
REGSET32_TLS,
53+
REGSET32_IOPERM,
5554
};
5655

56+
enum x86_regset_64 {
57+
REGSET64_GENERAL,
58+
REGSET64_FP,
59+
REGSET64_IOPERM,
60+
REGSET64_XSTATE,
61+
};
62+
63+
#define REGSET_GENERAL \
64+
({ \
65+
BUILD_BUG_ON((int)REGSET32_GENERAL != (int)REGSET64_GENERAL); \
66+
REGSET32_GENERAL; \
67+
})
68+
69+
#define REGSET_FP \
70+
({ \
71+
BUILD_BUG_ON((int)REGSET32_FP != (int)REGSET64_FP); \
72+
REGSET32_FP; \
73+
})
74+
75+
5776
struct pt_regs_offset {
5877
const char *name;
5978
int offset;
@@ -788,13 +807,13 @@ long arch_ptrace(struct task_struct *child, long request,
788807
#ifdef CONFIG_X86_32
789808
case PTRACE_GETFPXREGS: /* Get the child extended FPU state. */
790809
return copy_regset_to_user(child, &user_x86_32_view,
791-
REGSET_XFP,
810+
REGSET32_XFP,
792811
0, sizeof(struct user_fxsr_struct),
793812
datap) ? -EIO : 0;
794813

795814
case PTRACE_SETFPXREGS: /* Set the child extended FPU state. */
796815
return copy_regset_from_user(child, &user_x86_32_view,
797-
REGSET_XFP,
816+
REGSET32_XFP,
798817
0, sizeof(struct user_fxsr_struct),
799818
datap) ? -EIO : 0;
800819
#endif
@@ -1086,13 +1105,13 @@ static long ia32_arch_ptrace(struct task_struct *child, compat_long_t request,
10861105

10871106
case PTRACE_GETFPXREGS: /* Get the child extended FPU state. */
10881107
return copy_regset_to_user(child, &user_x86_32_view,
1089-
REGSET_XFP, 0,
1108+
REGSET32_XFP, 0,
10901109
sizeof(struct user32_fxsr_struct),
10911110
datap);
10921111

10931112
case PTRACE_SETFPXREGS: /* Set the child extended FPU state. */
10941113
return copy_regset_from_user(child, &user_x86_32_view,
1095-
REGSET_XFP, 0,
1114+
REGSET32_XFP, 0,
10961115
sizeof(struct user32_fxsr_struct),
10971116
datap);
10981117

@@ -1215,25 +1234,25 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
12151234
#ifdef CONFIG_X86_64
12161235

12171236
static struct user_regset x86_64_regsets[] __ro_after_init = {
1218-
[REGSET_GENERAL] = {
1237+
[REGSET64_GENERAL] = {
12191238
.core_note_type = NT_PRSTATUS,
12201239
.n = sizeof(struct user_regs_struct) / sizeof(long),
12211240
.size = sizeof(long), .align = sizeof(long),
12221241
.regset_get = genregs_get, .set = genregs_set
12231242
},
1224-
[REGSET_FP] = {
1243+
[REGSET64_FP] = {
12251244
.core_note_type = NT_PRFPREG,
12261245
.n = sizeof(struct fxregs_state) / sizeof(long),
12271246
.size = sizeof(long), .align = sizeof(long),
12281247
.active = regset_xregset_fpregs_active, .regset_get = xfpregs_get, .set = xfpregs_set
12291248
},
1230-
[REGSET_XSTATE] = {
1249+
[REGSET64_XSTATE] = {
12311250
.core_note_type = NT_X86_XSTATE,
12321251
.size = sizeof(u64), .align = sizeof(u64),
12331252
.active = xstateregs_active, .regset_get = xstateregs_get,
12341253
.set = xstateregs_set
12351254
},
1236-
[REGSET_IOPERM64] = {
1255+
[REGSET64_IOPERM] = {
12371256
.core_note_type = NT_386_IOPERM,
12381257
.n = IO_BITMAP_LONGS,
12391258
.size = sizeof(long), .align = sizeof(long),
@@ -1256,39 +1275,39 @@ static const struct user_regset_view user_x86_64_view = {
12561275

12571276
#if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION
12581277
static struct user_regset x86_32_regsets[] __ro_after_init = {
1259-
[REGSET_GENERAL] = {
1278+
[REGSET32_GENERAL] = {
12601279
.core_note_type = NT_PRSTATUS,
12611280
.n = sizeof(struct user_regs_struct32) / sizeof(u32),
12621281
.size = sizeof(u32), .align = sizeof(u32),
12631282
.regset_get = genregs32_get, .set = genregs32_set
12641283
},
1265-
[REGSET_FP] = {
1284+
[REGSET32_FP] = {
12661285
.core_note_type = NT_PRFPREG,
12671286
.n = sizeof(struct user_i387_ia32_struct) / sizeof(u32),
12681287
.size = sizeof(u32), .align = sizeof(u32),
12691288
.active = regset_fpregs_active, .regset_get = fpregs_get, .set = fpregs_set
12701289
},
1271-
[REGSET_XFP] = {
1290+
[REGSET32_XFP] = {
12721291
.core_note_type = NT_PRXFPREG,
12731292
.n = sizeof(struct fxregs_state) / sizeof(u32),
12741293
.size = sizeof(u32), .align = sizeof(u32),
12751294
.active = regset_xregset_fpregs_active, .regset_get = xfpregs_get, .set = xfpregs_set
12761295
},
1277-
[REGSET_XSTATE] = {
1296+
[REGSET32_XSTATE] = {
12781297
.core_note_type = NT_X86_XSTATE,
12791298
.size = sizeof(u64), .align = sizeof(u64),
12801299
.active = xstateregs_active, .regset_get = xstateregs_get,
12811300
.set = xstateregs_set
12821301
},
1283-
[REGSET_TLS] = {
1302+
[REGSET32_TLS] = {
12841303
.core_note_type = NT_386_TLS,
12851304
.n = GDT_ENTRY_TLS_ENTRIES, .bias = GDT_ENTRY_TLS_MIN,
12861305
.size = sizeof(struct user_desc),
12871306
.align = sizeof(struct user_desc),
12881307
.active = regset_tls_active,
12891308
.regset_get = regset_tls_get, .set = regset_tls_set
12901309
},
1291-
[REGSET_IOPERM32] = {
1310+
[REGSET32_IOPERM] = {
12921311
.core_note_type = NT_386_IOPERM,
12931312
.n = IO_BITMAP_BYTES / sizeof(u32),
12941313
.size = sizeof(u32), .align = sizeof(u32),
@@ -1311,10 +1330,10 @@ u64 xstate_fx_sw_bytes[USER_XSTATE_FX_SW_WORDS];
13111330
void __init update_regset_xstate_info(unsigned int size, u64 xstate_mask)
13121331
{
13131332
#ifdef CONFIG_X86_64
1314-
x86_64_regsets[REGSET_XSTATE].n = size / sizeof(u64);
1333+
x86_64_regsets[REGSET64_XSTATE].n = size / sizeof(u64);
13151334
#endif
13161335
#if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION
1317-
x86_32_regsets[REGSET_XSTATE].n = size / sizeof(u64);
1336+
x86_32_regsets[REGSET32_XSTATE].n = size / sizeof(u64);
13181337
#endif
13191338
xstate_fx_sw_bytes[USER_XSTATE_XCR0_WORD] = xstate_mask;
13201339
}

0 commit comments

Comments
 (0)