struct pt_regs { /* * NB: 32-bit x86 CPUs are inconsistent as what happens in the * following cases (where %seg represents a segment register): * * - pushl %seg: some do a 16-bit write and leave the high * bits alone * - movl %seg, [mem]: some do a 16-bit write despite the movl * - IDT entry: some (e.g. 486) will leave the high bits of CS * and (if applicable) SS undefined. * * Fortunately, x86-32 doesn't read the high bits on POP or IRET, * so we can just treat all of the segment registers as 16-bit * values.
*/ unsignedlong bx; unsignedlong cx; unsignedlong dx; unsignedlong si; unsignedlong di; unsignedlong bp; unsignedlong ax; unsignedshort ds; unsignedshort __dsh; unsignedshort es; unsignedshort __esh; unsignedshort fs; unsignedshort __fsh; /* * On interrupt, gs and __gsh store the vector number. They never * store gs any more.
*/ unsignedshort gs; unsignedshort __gsh; /* On interrupt, this is the error code. */ unsignedlong orig_ax; unsignedlong ip; unsignedshort cs; unsignedshort __csh; unsignedlong flags; unsignedlong sp; unsignedshort ss; unsignedshort __ssh;
};
#else/* __i386__ */
struct fred_cs { /* CS selector */
u64 cs : 16, /* Stack level at event time */
sl : 2, /* IBT in WAIT_FOR_ENDBRANCH state */
wfe : 1,
: 45;
};
struct fred_ss { /* SS selector */
u64 ss : 16, /* STI state */
sti : 1, /* Set if syscall, sysenter or INT n */
swevent : 1, /* Event is NMI type */
nmi : 1,
: 13, /* Event vector */
vector : 8,
: 8, /* Event type */
type : 4,
: 4, /* Event was incident to enclave execution */
enclave : 1, /* CPU was in long mode */
lm : 1, /* * Nested exception during FRED delivery, not set * for #DF.
*/
nested : 1,
: 1, /* * The length of the instruction causing the event. * Only set for INTO, INT1, INT3, INT n, SYSCALL * and SYSENTER. 0 otherwise.
*/
insnlen : 4;
};
struct pt_regs { /* * C ABI says these regs are callee-preserved. They aren't saved on * kernel entry unless syscall needs a complete, fully filled * "struct pt_regs".
*/ unsignedlong r15; unsignedlong r14; unsignedlong r13; unsignedlong r12; unsignedlong bp; unsignedlong bx;
/* These regs are callee-clobbered. Always saved on kernel entry. */ unsignedlong r11; unsignedlong r10; unsignedlong r9; unsignedlong r8; unsignedlong ax; unsignedlong cx; unsignedlong dx; unsignedlong si; unsignedlong di;
/* * orig_ax is used on entry for: * - the syscall number (syscall, sysenter, int80) * - error_code stored by the CPU on traps and exceptions * - the interrupt number for device interrupts * * A FRED stack frame starts here: * 1) It _always_ includes an error code; * * 2) The return frame for ERET[US] starts here, but * the content of orig_ax is ignored.
*/ unsignedlong orig_ax;
/* The IRETQ return frame starts here */ unsignedlong ip;
union { /* CS selector */
u16 cs; /* The extended 64-bit data slot containing CS */
u64 csx; /* The FRED CS extension */ struct fred_cs fred_cs;
};
unsignedlong flags; unsignedlong sp;
union { /* SS selector */
u16 ss; /* The extended 64-bit data slot containing SS */
u64 ssx; /* The FRED SS extension */ struct fred_ss fred_ss;
};
/* * Top of stack on IDT systems, while FRED systems have extra fields * defined above for storing exception related information, e.g. CR2 or * DR6.
*/
};
/* * user_mode(regs) determines whether a register set came from user * mode. On x86_32, this is true if V8086 mode was enabled OR if the * register set was from protected mode with RPL-3 CS value. This * tricky test checks that with one comparison. * * On x86_64, vm86 mode is mercifully nonexistent, and we don't need * the extra check.
*/ static __always_inline int user_mode(struct pt_regs *regs)
{ #ifdef CONFIG_X86_32 return ((regs->cs & SEGMENT_RPL_MASK) | (regs->flags & X86_VM_MASK)) >= USER_RPL; #else return !!(regs->cs & 3); #endif
}
static __always_inline int v8086_mode(struct pt_regs *regs)
{ #ifdef CONFIG_X86_32 return (regs->flags & X86_VM_MASK); #else return 0; /* No V86 mode support in long mode */ #endif
}
staticinlinebool user_64bit_mode(struct pt_regs *regs)
{ #ifdef CONFIG_X86_64 #ifndef CONFIG_PARAVIRT_XXL /* * On non-paravirt systems, this is the only long mode CPL 3 * selector. We do not allow long mode selectors in the LDT.
*/ return regs->cs == __USER_CS; #else /* Headers are too twisted for this to go in paravirt.h. */ return regs->cs == __USER_CS || regs->cs == pv_info.extra_user_64bit_cs; #endif #else/* !CONFIG_X86_64 */ returnfalse; #endif
}
/* * Determine whether the register set came from any context that is running in * 64-bit mode.
*/ staticinlinebool any_64bit_mode(struct pt_regs *regs)
{ #ifdef CONFIG_X86_64 return !user_mode(regs) || user_64bit_mode(regs); #else returnfalse; #endif
}
/* Query offset/name of register from its name/offset */ externint regs_query_register_offset(constchar *name); externconstchar *regs_query_register_name(unsignedint offset); #define MAX_REG_OFFSET (offsetof(struct pt_regs, ss))
/** * regs_get_register() - get register value from its offset * @regs: pt_regs from which register value is gotten. * @offset: offset number of the register. * * regs_get_register returns the value of a register. The @offset is the * offset of the register in struct pt_regs address which specified by @regs. * If @offset is bigger than MAX_REG_OFFSET, this returns 0.
*/ staticinlineunsignedlong regs_get_register(struct pt_regs *regs, unsignedint offset)
{ if (unlikely(offset > MAX_REG_OFFSET)) return 0; #ifdef CONFIG_X86_32 /* The selector fields are 16-bit. */ if (offset == offsetof(struct pt_regs, cs) ||
offset == offsetof(struct pt_regs, ss) ||
offset == offsetof(struct pt_regs, ds) ||
offset == offsetof(struct pt_regs, es) ||
offset == offsetof(struct pt_regs, fs) ||
offset == offsetof(struct pt_regs, gs)) { return *(u16 *)((unsignedlong)regs + offset);
/** * regs_within_kernel_stack() - check the address in the stack * @regs: pt_regs which contains kernel stack pointer. * @addr: address which is checked. * * regs_within_kernel_stack() checks @addr is within the kernel stack page(s). * If @addr is within the kernel stack, it returns true. If not, returns false.
*/ staticinlineint regs_within_kernel_stack(struct pt_regs *regs, unsignedlong addr)
{ return ((addr & ~(THREAD_SIZE - 1)) == (regs->sp & ~(THREAD_SIZE - 1)));
}
/** * regs_get_kernel_stack_nth_addr() - get the address of the Nth entry on stack * @regs: pt_regs which contains kernel stack pointer. * @n: stack entry number. * * regs_get_kernel_stack_nth() returns the address of the @n th entry of the * kernel stack which is specified by @regs. If the @n th entry is NOT in * the kernel stack, this returns NULL.
*/ staticinlineunsignedlong *regs_get_kernel_stack_nth_addr(struct pt_regs *regs, unsignedint n)
{ unsignedlong *addr = (unsignedlong *)regs->sp;
/* To avoid include hell, we can't include uaccess.h */ externlong copy_from_kernel_nofault(void *dst, constvoid *src, size_t size);
/** * regs_get_kernel_stack_nth() - get Nth entry of the stack * @regs: pt_regs which contains kernel stack pointer. * @n: stack entry number. * * regs_get_kernel_stack_nth() returns @n th entry of the kernel stack which * is specified by @regs. If the @n th entry is NOT in the kernel stack * this returns 0.
*/ staticinlineunsignedlong regs_get_kernel_stack_nth(struct pt_regs *regs, unsignedint n)
{ unsignedlong *addr; unsignedlong val; long ret;
addr = regs_get_kernel_stack_nth_addr(regs, n); if (addr) {
ret = copy_from_kernel_nofault(&val, addr, sizeof(val)); if (!ret) return val;
} return 0;
}
/** * regs_get_kernel_argument() - get Nth function argument in kernel * @regs: pt_regs of that context * @n: function argument number (start from 0) * * regs_get_argument() returns @n th argument of the function call. * Note that this chooses most probably assignment, in some case * it can be incorrect. * This is expected to be called from kprobes or ftrace with regs * where the top of stack is the return address.
*/ staticinlineunsignedlong regs_get_kernel_argument(struct pt_regs *regs, unsignedint n)
{ staticconstunsignedint argument_offs[] = { #ifdef __i386__
offsetof(struct pt_regs, ax),
offsetof(struct pt_regs, dx),
offsetof(struct pt_regs, cx), #define NR_REG_ARGUMENTS 3 #else
offsetof(struct pt_regs, di),
offsetof(struct pt_regs, si),
offsetof(struct pt_regs, dx),
offsetof(struct pt_regs, cx),
offsetof(struct pt_regs, r8),
offsetof(struct pt_regs, r9), #define NR_REG_ARGUMENTS 6 #endif
};
if (n >= NR_REG_ARGUMENTS) {
n -= NR_REG_ARGUMENTS - 1; return regs_get_kernel_stack_nth(regs, n);
} else return regs_get_register(regs, argument_offs[n]);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.