diff options
Diffstat (limited to 'arch/x86/kernel/ptrace.c')
-rw-r--r-- | arch/x86/kernel/ptrace.c | 112 |
1 files changed, 112 insertions, 0 deletions
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c index 8d7d5c9c1be3..a33a17d5d5c8 100644 --- a/arch/x86/kernel/ptrace.c +++ b/arch/x86/kernel/ptrace.c | |||
@@ -49,6 +49,118 @@ enum x86_regset { | |||
49 | REGSET_IOPERM32, | 49 | REGSET_IOPERM32, |
50 | }; | 50 | }; |
51 | 51 | ||
52 | struct pt_regs_offset { | ||
53 | const char *name; | ||
54 | int offset; | ||
55 | }; | ||
56 | |||
57 | #define REG_OFFSET_NAME(r) {.name = #r, .offset = offsetof(struct pt_regs, r)} | ||
58 | #define REG_OFFSET_END {.name = NULL, .offset = 0} | ||
59 | |||
60 | static const struct pt_regs_offset regoffset_table[] = { | ||
61 | #ifdef CONFIG_X86_64 | ||
62 | REG_OFFSET_NAME(r15), | ||
63 | REG_OFFSET_NAME(r14), | ||
64 | REG_OFFSET_NAME(r13), | ||
65 | REG_OFFSET_NAME(r12), | ||
66 | REG_OFFSET_NAME(r11), | ||
67 | REG_OFFSET_NAME(r10), | ||
68 | REG_OFFSET_NAME(r9), | ||
69 | REG_OFFSET_NAME(r8), | ||
70 | #endif | ||
71 | REG_OFFSET_NAME(bx), | ||
72 | REG_OFFSET_NAME(cx), | ||
73 | REG_OFFSET_NAME(dx), | ||
74 | REG_OFFSET_NAME(si), | ||
75 | REG_OFFSET_NAME(di), | ||
76 | REG_OFFSET_NAME(bp), | ||
77 | REG_OFFSET_NAME(ax), | ||
78 | #ifdef CONFIG_X86_32 | ||
79 | REG_OFFSET_NAME(ds), | ||
80 | REG_OFFSET_NAME(es), | ||
81 | REG_OFFSET_NAME(fs), | ||
82 | REG_OFFSET_NAME(gs), | ||
83 | #endif | ||
84 | REG_OFFSET_NAME(orig_ax), | ||
85 | REG_OFFSET_NAME(ip), | ||
86 | REG_OFFSET_NAME(cs), | ||
87 | REG_OFFSET_NAME(flags), | ||
88 | REG_OFFSET_NAME(sp), | ||
89 | REG_OFFSET_NAME(ss), | ||
90 | REG_OFFSET_END, | ||
91 | }; | ||
92 | |||
93 | /** | ||
94 | * regs_query_register_offset() - query register offset from its name | ||
95 | * @name: the name of a register | ||
96 | * | ||
97 | * regs_query_register_offset() returns the offset of a register in struct | ||
98 | * pt_regs from its name. If the name is invalid, this returns -EINVAL; | ||
99 | */ | ||
100 | int regs_query_register_offset(const char *name) | ||
101 | { | ||
102 | const struct pt_regs_offset *roff; | ||
103 | for (roff = regoffset_table; roff->name != NULL; roff++) | ||
104 | if (!strcmp(roff->name, name)) | ||
105 | return roff->offset; | ||
106 | return -EINVAL; | ||
107 | } | ||
108 | |||
109 | /** | ||
110 | * regs_query_register_name() - query register name from its offset | ||
111 | * @offset: the offset of a register in struct pt_regs. | ||
112 | * | ||
113 | * regs_query_register_name() returns the name of a register from its | ||
114 | * offset in struct pt_regs. If the @offset is invalid, this returns NULL; | ||
115 | */ | ||
116 | const char *regs_query_register_name(unsigned int offset) | ||
117 | { | ||
118 | const struct pt_regs_offset *roff; | ||
119 | for (roff = regoffset_table; roff->name != NULL; roff++) | ||
120 | if (roff->offset == offset) | ||
121 | return roff->name; | ||
122 | return NULL; | ||
123 | } | ||
124 | |||
125 | static const int arg_offs_table[] = { | ||
126 | #ifdef CONFIG_X86_32 | ||
127 | [0] = offsetof(struct pt_regs, ax), | ||
128 | [1] = offsetof(struct pt_regs, dx), | ||
129 | [2] = offsetof(struct pt_regs, cx) | ||
130 | #else /* CONFIG_X86_64 */ | ||
131 | [0] = offsetof(struct pt_regs, di), | ||
132 | [1] = offsetof(struct pt_regs, si), | ||
133 | [2] = offsetof(struct pt_regs, dx), | ||
134 | [3] = offsetof(struct pt_regs, cx), | ||
135 | [4] = offsetof(struct pt_regs, r8), | ||
136 | [5] = offsetof(struct pt_regs, r9) | ||
137 | #endif | ||
138 | }; | ||
139 | |||
140 | /** | ||
141 | * regs_get_argument_nth() - get Nth argument at function call | ||
142 | * @regs: pt_regs which contains registers at function entry. | ||
143 | * @n: argument number. | ||
144 | * | ||
145 | * regs_get_argument_nth() returns @n th argument of a function call. | ||
146 | * Since usually the kernel stack will be changed right after function entry, | ||
147 | * you must use this at function entry. If the @n th entry is NOT in the | ||
148 | * kernel stack or pt_regs, this returns 0. | ||
149 | */ | ||
150 | unsigned long regs_get_argument_nth(struct pt_regs *regs, unsigned int n) | ||
151 | { | ||
152 | if (n < ARRAY_SIZE(arg_offs_table)) | ||
153 | return *((unsigned long *)regs + arg_offs_table[n]); | ||
154 | else { | ||
155 | /* | ||
156 | * The typical case: arg n is on the stack. | ||
157 | * (Note: stack[0] = return address, so skip it) | ||
158 | */ | ||
159 | n -= ARRAY_SIZE(arg_offs_table); | ||
160 | return regs_get_kernel_stack_nth(regs, 1 + n); | ||
161 | } | ||
162 | } | ||
163 | |||
52 | /* | 164 | /* |
53 | * does not yet catch signals sent when the child dies. | 165 | * does not yet catch signals sent when the child dies. |
54 | * in exit.c or in signal.c. | 166 | * in exit.c or in signal.c. |