* The x86-64 Linux incarnation of arch-dependent OS-dependent
* routines. See also "linux-os.c".
*/
* This software is part of the SBCL system. See the README file for
* more information.
*
* This software is derived from the CMU CL system, which was
* written at Carnegie Mellon University and released into the
* public domain. The software is in the public domain and is
* provided with absolutely no warranty. See the COPYING and CREDITS
* files for more information.
*/
#define _GNU_SOURCE
#include <stdio.h>
#include <stddef.h>
#include <sys/param.h>
#include <sys/file.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
#include <sys/ucontext.h>
#include "./signal.h"
#include "os.h"
#include "arch.h"
#include "globals.h"
#include "interrupt.h"
#include "interr.h"
#include "lispregs.h"
#include "sbcl.h"
#include <sys/types.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <unistd.h>
#include <linux/unistd.h>
#include <sys/mman.h>
#include <linux/version.h>
#include "thread.h"
#include "validate.h"
int arch_os_thread_init(struct thread *thread) {
stack_t sigstack;
#ifdef LISP_FEATURE_C_STACK_IS_CONTROL_STACK
* we had better use an alternate stack for whatever signal tells us
* we've exhausted it */
sigstack.ss_sp = calc_altstack_base(thread);
sigstack.ss_flags = 0;
sigstack.ss_size = calc_altstack_size(thread);
if(sigaltstack(&sigstack,0)<0) {
lose("Cannot sigaltstack: %s",strerror(errno));
}
#endif
#ifdef MEMORY_SANITIZER
extern __thread unsigned long __msan_param_tls[];
((lispobj*)thread)[THREAD_MSAN_PARAM_TLS_SLOT] = (uword_t)&__msan_param_tls[0];
#endif
return 1;
}
* defunct. Not called on live threads
*/
int arch_os_thread_cleanup(struct thread __attribute__((unused)) *thread) {
return 1;
}
static unsigned char regmap[16] = {
REG_RAX, REG_RCX, REG_RDX, REG_RBX, REG_RSP, REG_RBP, REG_RSI, REG_RDI,
REG_R8, REG_R9, REG_R10, REG_R11, REG_R12, REG_R13, REG_R14, REG_R15
};
static char *gprnames[] = {
"rax","rcx","rdx","rbx","rsp","rbp","rsi","rdi",
"r8","r9","r10","r11","r12","r13","r14","r15"
};
static char *fprnames[] = {
"xmm0","xmm1","xmm2","xmm3","xmm4","xmm5","xmm6","xmm7",
"xmm8","xmm9","xmm10","xmm11","xmm12","xmm13","xmm14","xmm15"
};
static char *flagbits[] = {"CF",0,"PF",0,"AF",0,"ZF","SF","TF","IF","DF","OF"};
void sb_dump_mcontext(char *reason, ucontext_t* context)
{
* we want to try to avoid interleaving their output.
* Using a single write() call usually does the trick */
char obuf[2048], smallbuf[100];
int bit, ptr = 0, i, j;
smallbuf[0] = smallbuf[1] = 0;
long unsigned int flags = context->uc_mcontext.gregs[REG_EFL];
for (bit=11; bit>=0; --bit)
if (flagbits[bit] && (flags & (1<<bit)))
ptr += sprintf(smallbuf+ptr, " %s", flagbits[bit]);
#define REMAINING sizeof obuf - ptr
ptr = 0;
ptr = snprintf(obuf, REMAINING,
THREAD_ID_LABEL" CPU state (%s): PC=%lx Flags={%s}\n",
THREAD_ID_VALUE, reason,
(uword_t)context->uc_mcontext.gregs[REG_RIP],
smallbuf+1);
for(i=0; i<2; ++i) {
for(j=0; j<8; ++j) ptr += snprintf(obuf+ptr, REMAINING, " %16s", gprnames[i*8+j]);
if (REMAINING) obuf[ptr++] = '\n';
for(j=0; j<8; ++j)
ptr += snprintf(obuf+ptr, REMAINING, " %16lX",
(uword_t)context->uc_mcontext.gregs[regmap[i*8+j]]);
if (REMAINING) obuf[ptr++] = '\n';
}
for(i=0; i<4; ++i) {
for(j=0; j<4; ++j) ptr += snprintf(obuf+ptr, REMAINING, " %32s", fprnames[i*4+j]);
if (REMAINING) obuf[ptr++] = '\n';
for(j=0; j<4; ++j) {
uint32_t* e = context->uc_mcontext.fpregs->_xmm[i*4+j].element;
ptr += snprintf(obuf+ptr, REMAINING, " %08X%08X%08X%08X", e[3], e[2], e[1], e[0]);
}
if (REMAINING) obuf[ptr++] = '\n';
}
sigset_tostring(&context->uc_sigmask, smallbuf, sizeof smallbuf);
ptr += snprintf(obuf+ptr, REMAINING, "sigmask=%s\n", smallbuf);
write(2, obuf, ptr);
}
os_context_register_t *
os_context_register_addr(os_context_t *context, int offset)
{
if (offset >= 0 && offset < 16)
return (os_context_register_t*)&context->uc_mcontext.gregs[regmap[offset]];
return 0;
}
os_context_register_t *
os_context_pc_addr(os_context_t *context)
{
return (os_context_register_t*)&context->uc_mcontext.gregs[REG_RIP];
}
os_context_register_t *
os_context_sp_addr(os_context_t *context)
{
return (os_context_register_t*)&context->uc_mcontext.gregs[REG_RSP];
}
os_context_register_t *
os_context_fp_addr(os_context_t *context)
{
return (os_context_register_t*)&context->uc_mcontext.gregs[REG_RBP];
}
unsigned long
os_context_fp_control(os_context_t *context)
{
return (uintptr_t)&context->uc_mcontext.gregs[REG_RSP];
}
os_context_register_t *
os_context_float_register_addr(os_context_t *context, int offset)
{
return (os_context_register_t*)&context->uc_mcontext.fpregs->_xmm[offset];
}
sigset_t *
os_context_sigmask_addr(os_context_t *context)
{
return &context->uc_sigmask;
}
void NO_SANITIZE_ADDRESS
os_restore_fp_control(os_context_t *context)
{
if (context->uc_mcontext.fpregs) {
unsigned int temp = (context->uc_mcontext.fpregs->mxcsr) & ~0x3F;
asm ("ldmxcsr %0" : : "m" (temp));
asm ("fldcw %0" : : "m" (context->uc_mcontext.fpregs->cwd));
}
}
void
os_flush_icache(os_vm_address_t __attribute__((unused)) address,
os_vm_size_t __attribute__((unused)) length)
{
}
#include <math.h>
const long libm_anchor = (long)acos;