Hello !
We have a xenomai application that uses mprotect to change write
protection in order to set and clear breakpoint codes.
This works quite well (the code invoking mprotect switches to linux,
but thats ok).
The problem is that from time to time the realtime task executing code
in the area changed with mprotect also switches domains to handle a page
fault.
Is there some functionality in xenomai to change memory protection not
using mprotect ?
Attached you find a short sample that can reproduce this problem.
Thanks Michael
/*
* Description:
*
* mprotect test
*/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <rtdm/rtdm.h>
#include <native/task.h>
#include <native/timer.h>
#include <native/mutex.h>
#include <rtdk.h>
#include <signal.h>
#include <execinfo.h>
#define NUM_LOOPS 1000000
#define RTT_PRIO 99
RT_TASK rt_task_desc;
static int finished = 0;
///////////////////////////////////////////////////
// defined from xenomai syscall.h
#define SIGDEBUG_UNDEFINED 0
#define SIGDEBUG_MIGRATE_SIGNAL 1
#define SIGDEBUG_MIGRATE_SYSCALL 2
#define SIGDEBUG_MIGRATE_FAULT 3
#define SIGDEBUG_MIGRATE_PRIOINV 4
#define SIGDEBUG_NOMLOCK 5
#define SIGDEBUG_WATCHDOG 6
///////////////////////////////////////////////////
// own defined
#define SIGDEBUG_STOPTHREAD 17
static const char *GetSIGXCPUsubCode(int subSig) {
if (subSig == SIGDEBUG_UNDEFINED) return "SD_UNDEFINED";
if (subSig == SIGDEBUG_MIGRATE_SIGNAL) return "SD_MIGRATE_SIGNAL";
if (subSig == SIGDEBUG_MIGRATE_SYSCALL) return "SD_MIGRATE_SYSCALL";
if (subSig == SIGDEBUG_MIGRATE_FAULT) return "SD_MIGRATE_FAULT";
if (subSig == SIGDEBUG_MIGRATE_PRIOINV) return "SD_MIGRATE_PRIOINV";
if (subSig == SIGDEBUG_NOMLOCK) return "SD_NOMLOCK";
if (subSig == SIGDEBUG_WATCHDOG) return "SD_WATCHDOG";
if (subSig == SIGDEBUG_STOPTHREAD) return "SD_STOPTHREAD";
return "???";
}
static void warn_upon_switch(int sig, siginfo_t *info, void *context)
{
if (sig == SIGXCPU) {
printf("received SIGXCPU\n");
printf("SIGXCPU subcode: %s\n", GetSIGXCPUsubCode(info->si_value.sival_int));
finished = 1;
}
}
/* This is the realtime task */
static void rt_task_proc(void *arg)
{
unsigned long long counter = 0;
rt_task_set_mode(0, T_WARNSW, NULL);
if (rt_task_set_periodic(NULL, TM_NOW, 100000)) {
rt_printf("failed to set high periodic\n");
return;
}
while (!finished) {
rt_task_wait_period(NULL);
if (counter > 1000) {
counter = 0;
rt_printf(".");
}
}
}
void foo(void)
{
printf("foo\n");
}
int main(int argc, char *argv[])
{
int ret;
int flags = PROT_READ | PROT_EXEC;
uint8_t awl_orig_instr = 0;
const uint8_t awl_break_code = 0xcc;
char * addr = NULL;
struct sigaction sa_new, sa_old;
int counter = 1;
sa_new.sa_sigaction = warn_upon_switch;
sa_new.sa_flags = SA_SIGINFO /* Invoke signal-catching function with
three arguments instead of one. */
| SA_NODEFER; /* Don't automatically block the signal when
its handler is being executed. */
sigemptyset(&sa_new.sa_mask);
if (sigaction(SIGXCPU, &sa_new, &sa_old) < 0) {
printf("failed to install signal handler for SIGXCPU\n");
exit(1);
}
rt_task_set_mode(0, T_WARNSW, NULL);
/* No memory-swapping for this programm */
ret = mlockall(MCL_CURRENT | MCL_FUTURE);
if (ret) {
perror("ERROR : mlockall has failled");
exit(1);
}
printf("foo = %p rt_task_proc=%p\n", &foo, &rt_task_proc);
addr = &rt_task_proc - ((int)(&rt_task_proc) & (0x1000 - 1));
printf("addr = %p\n", addr);
if (rt_task_shadow(NULL, "main", 50, 0)) {
printf("failed to shadow main task\n");
exit(1);
}
rt_print_auto_init(1);
/*
* Turn the current linux task into a xenomai RT-task
* highest priority
*/
ret = rt_task_create(&rt_task_desc, "RTT", 0, RTT_PRIO, T_JOINABLE);
if (ret) {
fprintf(stderr, "ERROR : rt_task_create: %s\n",
strerror(-ret));
exit(1);
}
rt_printf("Created task\n");
ret = rt_task_start(&rt_task_desc, &rt_task_proc, NULL);
if (ret) {
fprintf(stderr, "ERROR : rt_task_start: %s\n",
strerror(-ret));
exit(1);
}
rt_printf("Started task\n");
while (!finished) {
flags = PROT_READ | PROT_EXEC | PROT_WRITE;
mprotect(addr , 0x1000, flags);
// set breakpoint code
if (!awl_orig_instr) {
memcpy(&awl_orig_instr, &foo, sizeof(awl_orig_instr));
memcpy(&foo, &awl_break_code, sizeof(awl_break_code));
}
// restore original code
else {
memcpy(&foo, &awl_orig_instr, sizeof(awl_orig_instr));
awl_orig_instr = 0;
}
//rt_printf("- removing memory protection\n");
flags = PROT_READ | PROT_EXEC;
mprotect(addr, 0x1000, flags);
if (counter++ > 10) {
counter = 1;
}
usleep(counter);
}
rt_task_join(&rt_task_desc);
printf("Task joined\n");
return 0;
}
_______________________________________________
Xenomai-help mailing list
[email protected]
https://mail.gna.org/listinfo/xenomai-help