Compilation error using rest and rime together in Cooja - c

I am trying to create a ContikiOS firmware that acts as a gateway using Rime and REST. The gateway must communicate to other motes with the Rime mesh, and can communicate to the outside via a REST API.
The following code is a combination from two default Contiki examples (rest-example/rest-server-example.c and rime/example-mesh.c). Therefore I include "rest.h", "net/rime.h", "net/rime/mesh.h".
The problem is when I try to compile this firmware using following makefile, the rime files don't get included into obj_sky and any Rime functions I use in the firmware get an 'undefined reference' error. However when I remove the lines in the makefile and any code referring to REST in the firmware code, it does compile (and adds the rime files to obj_sky).
Would anyone have an idea why rime does not get added after adding the rest-http app and what I can do to have it compile?
Thank you
Code
Compiler info
> make gateway.sky TARGET=sky
CC gateway.c
CC ../../platform/sky/./contiki-sky-main.c
LD gateway.sky
/usr/lib/gcc/msp430/4.6.3/../../../../msp430/bin/ld: gateway.sky section `.data' will not fit in region `rom'
/usr/lib/gcc/msp430/4.6.3/../../../../msp430/bin/ld: section .vectors loaded at [000000000000ffe0,000000000000ffff] overlaps section .data loaded at [000000000000ff0c,0000000000010037]
/usr/lib/gcc/msp430/4.6.3/../../../../msp430/bin/ld: region `rom' overflowed by 88 bytes
gateway.co: In function `process_thread_init_mesh':
gateway.c:(.text.process_thread_init_mesh+0x10): undefined reference to `mesh_close'
gateway.c:(.text.process_thread_init_mesh+0x26): undefined reference to `mesh_open'
gateway.co: In function `recv':
gateway.c:(.text.recv+0x48): undefined reference to `mesh_send'
gateway.co: In function `enable_handler':
gateway.c:(.text.enable_handler+0x80): undefined reference to `mesh_send'
collect2: ld returned 1 exit status
../../Makefile.include:254: recipe for target 'gateway.sky' failed
Process returned error code 2
make: *** [gateway.sky] Error 1
rm obj_sky/contiki-sky-main.o gateway.co
Makefile
all: gateway mote
ifndef TARGET
TARGET=sky
endif
CONTIKI=../..
WITH_UIP6=1
UIP_CONF_IPV6=1
WITH_COAP = 0
APPS += rest-http
include $(CONTIKI)/Makefile.include
Lines to compile for REST
WITH_UIP6=1
UIP_CONF_IPV6=1
WITH_COAP = 0
APPS += rest-http
gateway.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "contiki.h"
#include "contiki-net.h"
#include "rest.h"
#include "net/rime.h"
#include "net/rime/mesh.h"
#if defined (PLATFORM_HAS_LIGHT)
#include "dev/light-sensor.h"
#endif
#if defined (PLATFORM_HAS_BATT)
#include "dev/battery-sensor.h"
#endif
#if defined (PLATFORM_HAS_SHT11)
#include "dev/sht11-sensor.h"
#endif
#if defined (PLATFORM_HAS_LEDS)
#include "dev/leds.h"
#endif
#define DEBUG 1
#if DEBUG
#include <stdio.h>
#define PRINTF(...) printf(__VA_ARGS__)
#define PRINT6ADDR(addr) PRINTF(" %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x ", ((uint8_t *)addr)[0], ((uint8_t *)addr)[1], ((uint8_t *)addr)[2], ((uint8_t *)addr)[3], ((uint8_t *)addr)[4], ((uint8_t *)addr)[5], ((uint8_t *)addr)[6], ((uint8_t *)addr)[7], ((uint8_t *)addr)[8], ((uint8_t *)addr)[9], ((uint8_t *)addr)[10], ((uint8_t *)addr)[11], ((uint8_t *)addr)[12], ((uint8_t *)addr)[13], ((uint8_t *)addr)[14], ((uint8_t *)addr)[15])
#define PRINTLLADDR(lladdr) PRINTF(" %02x:%02x:%02x:%02x:%02x:%02x ",(lladdr)->addr[0], (lladdr)->addr[1], (lladdr)->addr[2], (lladdr)->addr[3],(lladdr)->addr[4], (lladdr)->addr[5])
#else
#define PRINTF(...)
#define PRINT6ADDR(addr)
#define PRINTLLADDR(addr)
#endif
#define MESSAGE "Hello"
/*---------------------------------------------------------------------------*/
/*---------------------------------RIME--------------------------------------*/
/*---------------------------------------------------------------------------*/
static struct mesh_conn mesh;
PROCESS(init_mesh, "RIME Mesh");
/*---------------------------------------------------------------------------*/
static void
sent(struct mesh_conn *c)
{
printf("packet sent\n");
}
static void
timedout(struct mesh_conn *c)
{
printf("packet timedout\n");
}
static void
recv(struct mesh_conn *c, const rimeaddr_t *from, uint8_t hops)
{
printf("Data received from %d.%d: %.*s (%d)\n",
from->u8[0], from->u8[1],
packetbuf_datalen(), (char *)packetbuf_dataptr(), packetbuf_datalen());
packetbuf_copyfrom(MESSAGE, strlen(MESSAGE));
mesh_send(&mesh, from);
}
static void
send(int to, char * msg)
{
printf("Sending data to %d", to);
rimeaddr_t addr;
packetbuf_copyfrom(msg, strlen(msg));
addr.u8[0] = to;
addr.u8[1] = 0;
mesh_send(&mesh, &addr);
}
const static struct mesh_callbacks callbacks = {recv, sent, timedout};
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(init_mesh, ev, data)
{
PROCESS_EXITHANDLER(mesh_close(&mesh);)
PROCESS_BEGIN();
mesh_open(&mesh, 132, &callbacks);
PROCESS_END();
}
/*---------------------------------------------------------------------------*/
/*----------------------------------REST-------------------------------------*/
/*---------------------------------------------------------------------------*/
RESOURCE(enable, METHOD_GET, "enable");
void
enable_handler(REQUEST* request, RESPONSE* response)
{
int moteId = 0;
char moteIdstr[12];
sprintf(moteIdstr, "%d", moteId);
char command[20];
char responseText[255];
if (rest_get_query_variable(request, "moteId", moteIdstr, 10)) {
PRINTF("moteId %s\n", moteIdstr);
send(moteId, command);
sprintf(responseText,"Command execute for mote %s!\n", moteIdstr);
} else {
sprintf(responseText,"Mote not available!\n");
}
rest_set_header_content_type(response, TEXT_PLAIN);
rest_set_response_payload(response, (uint8_t*)responseText, strlen(responseText));
}
PROCESS(gateway_rest, "Gateway Rest");
PROCESS_THREAD(gateway_rest, ev, data)
{
PROCESS_BEGIN();
#ifdef WITH_COAP
PRINTF("COAP Server\n");
#else
PRINTF("HTTP Server\n");
#endif
rest_init();
rest_activate_resource(&resource_enable);
//rest_activate_resource(&resource_disable);
PROCESS_END();
}
/*---------------*/
AUTOSTART_PROCESSES(&init_mesh, &gateway_rest);
Info
I am using Sky motes to compile the code in Cooja.

Related

The ebpf program(sockops) does not take effective when attaching into a child cgroup

I wrote an ebpf code to set tos of ip header, it take effective when attaching into the root path (1/sys/fs/cgroup/unified1), but it does not take effective when attaching into the child cgroup such as /sys/fs/cgroup/unified/docker/
code:
#include <linux/bpf.h>
#include <linux/if_ether.h>
#include <linux/if_packet.h>
#include <linux/ip.h>
#include <linux/in.h>
#include <linux/socket.h>
#include "bpf_helpers.h"
//#ifndef __section
//# define __section(NAME) \
// __attribute__((section(NAME), used))
//#endif
//
#ifndef BPF_FUNC
#define BPF_FUNC(NAME, ...) \
(*NAME)(__VA_ARGS__) = (void *) BPF_FUNC_##NAME
#endif
static void BPF_FUNC(trace_printk, const char *fmt, int fmt_size, ...);
#ifndef printk
# define printk(fmt, ...) \
({ \
char ____fmt[] = fmt; \
trace_printk(____fmt, sizeof(____fmt), ##__VA_ARGS__); \
})
#endif
SEC("sockops")
int set_initial_rto(struct bpf_sock_ops *skops)
{
int tos = 0x38;
int op = (int) skops->op;
printk("remote %x, op=%d tos %d\n",skops->remote_ip4, op,tos);
switch (op) {
case BPF_SOCK_OPS_TCP_CONNECT_CB:
case BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB:
case BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB:
printk("set tos %d",tos);
bpf_setsockopt(skops,IPPROTO_IP, IP_TOS, &tos, sizeof(tos));
break;
}
return 1;
}
char _license[] SEC("license") = "GPL";
Server env:
Ubuntu
kernel version : 5.4.0-77
bpf status:
# bpftool cgroup tree
CgroupPath
ID AttachType AttachFlags Name
/sys/fs/cgroup/unified/docker
10544 sock_ops set_tos
expected:
I can capture the package by tcpdump
actually:
tcpdump can't capture any package with DSCP mark
$ sudo tcpdump -vv -n ip -c 10 -i bond0.1000 and ip[1]=56
tcpdump: listening on bond0.1000, link-type EN10MB (Ethernet), capture size 262144 bytes
BTW, tcpdump can capture the package with DSCP mark if I attach the bpf prog to /sys/fs/cgroup/unified/

I have a function call in one program and this function is depreciated.Is there any newer version that I can use in my code | perf_buffer__new in ebpf

I have this function which is depreciated. First how one can find the new alternative to functions that are depreciated. the function exist in libbpf library and perf_buffer__new is the exact name. so basically as the name suggest its used to create perf buffer to share info between userspace and kernel. First I like to know is perf buffers are only specific to ebpf filters or not. not means I can use perf buffers in anything. for example if I have some driver code so I just add perf buffer to have info shared between some userspace app and the driver. so some searching on the web I found it specifically link to ebpf, is this true?
So this is my code that uses call to perf_buffer__new but that function is depreciated, this function in libbpf's libbpf.h header file declarations is commented out
So I like to new what is the new alternative that I can use in my code, if there is a change in api then i like to let u know that I am trying share buffer parameter in SEC("kprobe/__x64_sys_recvfrom") to userspace for that I have used PT_REGS_PARM2 and bpf_probe_read_kernel to and included the parameter in map data. So if api is changed then how to accomplish this this is my userspace and ebpf program
Userspace.c
// SPDX-License-Identifier: GPL-2.0-only
#include <stdio.h>
#include <fcntl.h>
#include <poll.h>
#include <time.h>
#include <signal.h>
#include <bpf/libbpf.h>
//create .o file root#this:/home/ubuntu/Desktop/ebpf/kern# clang -I /lib/modules/5.14.1/build -I /usr/include/bpf/ -O2 -Wall -c trace_output_user.c
static __u64 time_get_ns(void)
{
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return ts.tv_sec * 1000000000ull + ts.tv_nsec;
}
static __u64 start_time;
static __u64 cnt;
#define MAX_CNT 100000ll
static void print_bpf_output(void *ctx, int cpu, void *data, __u32 size)
{
struct {
int pid;
char cookie[90];
char *buf;
} *e = data;
int i=0;
printf("hello\n");
printf(" _____________________________________________________%d \n________%s\n",e->pid,e->buf);
i++;
//printf("received map value = %s\n",e->cookie);
/*if (e->cookie != 0x12345678) {
printf("BUG pid %llx cookie %d sized %d\n",
e->pid, e->cookie, size);
return;
}
cnt++;
if (cnt == MAX_CNT) {
printf("recv %lld events per sec\n",
MAX_CNT * 1000000000ll / (time_get_ns() - start_time));
return;
}*/
}
int main(int argc, char **argv)
{
struct perf_buffer_opts pb_opts = {};
struct bpf_link *link = NULL;
struct bpf_program *prog;
struct perf_buffer *pb;
struct bpf_object *obj;
int map_fd, ret = 0;
char filename[256];
FILE *f;
//snprintf(filename, sizeof(filename), "..o", argv[0]);
obj = bpf_object__open_file("./kprobe_send.o", NULL);
if (libbpf_get_error(obj)) {
fprintf(stderr, "ERROR: opening BPF object file failed\n");
return 0;
}
/* load BPF program */
if (bpf_object__load(obj)) {
fprintf(stderr, "ERROR: loading BPF object file failed\n");
goto cleanup;
}
map_fd = bpf_object__find_map_fd_by_name(obj, "my_map");
if (map_fd < 0) {
fprintf(stderr, "ERROR: finding a map in obj file failed\n");
goto cleanup;
}
printf("before\n");
prog = bpf_object__find_program_by_name(obj, "bpf_prog1");
if (libbpf_get_error(prog)) {
fprintf(stderr, "ERROR: finding a prog in obj file failed\n");
goto cleanup;
}
printf("after\n");
link = bpf_program__attach(prog);
printf("after\n");
if (libbpf_get_error(link)) {
fprintf(stderr, "ERROR: bpf_program__attach failed\n");
link = NULL;
goto cleanup;
}
printf("after\n");
pb_opts.sample_cb = print_bpf_output;
pb = perf_buffer__new_deprecated(map_fd, 8, &pb_opts);//error
printf("after\n");
ret = libbpf_get_error(pb);
if (ret) {
printf("failed to setup perf_buffer: %d\n", ret);
return 1;
}
f = popen("taskset 1 dd if=/dev/zero of=/dev/null", "r");
(void) f;
start_time = time_get_ns();
while ((ret = perf_buffer__poll(pb, 1000)) >= 0 && cnt < MAX_CNT) {
}
kill(0, SIGINT);
cleanup:
bpf_link__destroy(link);
bpf_object__close(obj);
return ret;
}
Kernel.c
#include <linux/ptrace.h>
#include <linux/version.h>
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
#include <string.h>
#include <sys/sendfile.h>
#include <time.h>
#include <stdlib.h>
#include <stdio.h>
#include </usr/include/bpf/bpf_tracing.h>
#include <linux/seccomp.h>
#define RAND_MAX 0x7fff
#define PERF_SAMPLE_RAW 1U << 0
#define randrange(N) rand() / (RAND_MAX/(N) + 1)
#define MAX 100000000 /* Values will be in the range (1 .. MAX) */
struct {
__uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
__uint(key_size, sizeof(int));
__uint(value_size, sizeof(int));
__uint(max_entries, 100);
} my_map SEC(".maps");
SEC("kprobe/__x64_sys_recvfrom")
int bpf_prog1(struct pt_regs *ctx)
{
static int vektor[100000000];
int candidates[MAX];
int i;
long key;
//srand(time(NULL)); /* Seed the random number generator. */
/*for (i=0; i<MAX; i++)
candidates[i] = i;
for (i = 0; i < MAX-1; i++) {
int c = randrange(MAX-i);
int t = candidates[i];
candidates[i] = candidates[i+c];
candidates[i+c] = t;
}
for (i=0; i<10; i++)
vektor[i] = candidates[i] + 1;*/
struct S {
int pid;
char cookie[90];
char *ptr;
} data={1,""};
//char *ptr = PT_REGS_PARM2(ctx);
struct seccomp_data sd;
bpf_probe_read_kernel(&sd, sizeof(sd), (void *)PT_REGS_PARM2(ctx));
if (sd.args[2] > 128 && sd.args[2] <= 1024) {
char fmt[] = "read(fd=%d, buf=%p, size=%d)\n";
bpf_trace_printk(fmt, sizeof(fmt),
sd.args[0], sd.args[1], sd.args[2]);
data.ptr=(char *)sd.args[1];
// memcpy(data.ptr,sd.args[1],sizeof(char)*220);
}
//data.pid =count;// bpf_get_current_pid_tgid();
//if(buf==NULL)
//memcpy(data.cookie,buf,20);
//data.ptr=ptr;
// data.cookie[0]=buf[0];
//bpf_get_current_comm(&data.cookie, sizeof(data.cookie));
//key=vektor[i];
//bpf_map_update_elem(fd,&key,&data,BPF_ANY);
//bpf_perf_event_output(ctx, &my_map, 1, &data, sizeof(data));
return 0;
}
char _license[] SEC("license") = "GPL";
int _version SEC("version") = 99;
when I compile and link the program userspace with root#this:/home/ubuntu/Desktop/ebpf/Linux-exFilter-main/pkg/probe/bpf# clang -v trace_output_user.c -o trace -lbpf
I get error that and warning
trace_output_user.c:101:7: warning: 'perf_buffer__new_deprecated' is deprecated: libbpf v0.7+: use new variant of perf_buffer__new() instead [-Wdeprecated-declarations]
pb = perf_buffer__new_deprecated(map_fd, 8, &pb_opts);
^
/usr/include/bpf/libbpf.h:949:12: note: 'perf_buffer__new_deprecated' has been explicitly marked deprecated here
LIBBPF_API LIBBPF_DEPRECATED_SINCE(0, 7, "use new variant of perf_buffer__new() instead")
^
/usr/include/bpf/libbpf_common.h:24:4: note: expanded from macro 'LIBBPF_DEPRECATED_SINCE'
(LIBBPF_DEPRECATED("libbpf v" # major "." # minor "+: " msg))
^
/usr/include/bpf/libbpf_common.h:19:47: note: expanded from macro 'LIBBPF_DEPRECATED'
#define LIBBPF_DEPRECATED(msg) __attribute__((deprecated(msg)))
^
1 warning generated.
"/usr/bin/ld" -z relro --hash-style=gnu --build-id --eh-frame-hdr -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o trace /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../x86_64-linux-gnu/crt1.o /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../x86_64-linux-gnu/crti.o /usr/bin/../lib/gcc/x86_64-linux-gnu/10/crtbegin.o -L/usr/bin/../lib/gcc/x86_64-linux-gnu/10 -L/usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../x86_64-linux-gnu -L/usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../lib64 -L/lib/x86_64-linux-gnu -L/lib/../lib64 -L/usr/lib/x86_64-linux-gnu -L/usr/lib/../lib64 -L/usr/lib/x86_64-linux-gnu/../../lib64 -L/usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../.. -L/usr/lib/llvm-12/bin/../lib -L/lib -L/usr/lib /tmp/trace_output_user-ec780e.o -lbpf -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/bin/../lib/gcc/x86_64-linux-gnu/10/crtend.o /usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../x86_64-linux-gnu/crtn.o
/usr/bin/ld: /tmp/trace_output_user-ec780e.o: in function `main':
trace_output_user.c:(.text+0x1e2): undefined reference to `perf_buffer__new_deprecated'
some details
perf_buffer__new_deprecated
and
perf_buffer__new are depreciated in latest version of libbpf
My kernel version is 5.14.1
1. you are explicitly using perf_buffer__new_deprecated in your code - don't do this: Use perf_buffer_new instead. You should never call a function that already has 'deprecated' in it's name.
2. Take a look in the header:
libbpf/libbpf.h
perf_buffer_new is defined like this:
#define perf_buffer__new(...) ___libbpf_overload(___perf_buffer_new, __VA_ARGS__)
#define ___perf_buffer_new6(map_fd, page_cnt, sample_cb, lost_cb, ctx, opts) \
perf_buffer__new(map_fd, page_cnt, sample_cb, lost_cb, ctx, opts)
#define ___perf_buffer_new3(map_fd, page_cnt, opts) \
perf_buffer__new_deprecated(map_fd, page_cnt, opts)
So there are 2 functions:
Old: pef_buffer_new with 3 arguments
New: perf_buffer_new with 6 arguments.
With the macros, libbpf makes old code compile, too, while telling you to change your function call.
You are using the old version right now (with 3 arguments). Switch to the new version with 6 arguments, as the 3-arguments-variant will be removed.
The new function (see libbpf/libbpf.h):
/**
* #brief **perf_buffer__new()** creates BPF perfbuf manager for a specified
* BPF_PERF_EVENT_ARRAY map
* #param map_fd FD of BPF_PERF_EVENT_ARRAY BPF map that will be used by BPF
* code to send data over to user-space
* #param page_cnt number of memory pages allocated for each per-CPU buffer
* #param sample_cb function called on each received data record
* #param lost_cb function called when record loss has occurred
* #param ctx user-provided extra context passed into *sample_cb* and *lost_cb*
* #return a new instance of struct perf_buffer on success, NULL on error with
* *errno* containing an error code
*/
LIBBPF_API struct perf_buffer *
perf_buffer__new(int map_fd, size_t page_cnt,
perf_buffer_sample_fn sample_cb, perf_buffer_lost_fn lost_cb, void *ctx,
const struct perf_buffer_opts *opts);
You can find the definitions for sample_cb and lost_cb in the header as well:
From above, we know sample_cb has the type perf_buffer_sample_fn. For the other callback, it is similar.
Both are defined in libbpf.h:
typedef void (*perf_buffer_sample_fn)(void *ctx, int cpu,
void *data, __u32 size);
typedef void (*perf_buffer_lost_fn)(void *ctx, int cpu, __u64 cnt);
See libbpf/libbpf.h
So a valid callback function could be
void myCallbackForNewData(void* ctx, int cpu, void*data, __u32 size) {}
Be aware that ctx* has nothing to do with BPF - it is something you can freely define in perf_buffer__new. This is useful if you use the same handler for multiple perf_buffers. Otherwise, you can just enter NULL.

Unable to update project conf variable in program

I want to update value of a variable at run time, present in project configuration as per some condition. But currently I am getting this error:
error: lvalue required as left operand of assignment
Actual code:
#include "contiki.h"
#include <stdio.h> /* For printf() */
/*---------------------------------------------------------------------------*/
PROCESS(hello_world_process, "Hello world process");
AUTOSTART_PROCESSES(&hello_world_process);
static void update_project_conf_value(void)
{
printf("Original Value: %d\n",TEST_VALUE);
TEST_VALUE = 0;
printf("After update: %d\n",TEST_VALUE);
}
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(hello_world_process, ev, data)
{
PROCESS_BEGIN();
update_project_conf_value();
PROCESS_END();
}
/*---------------------------------------------------------------------------*/
Project configuration:
#ifndef PROJECT_CONF_H_
#define PROJECT_CONF_H_
#define TEST_VALUE 1
/*---------------------------------------------------------------------------*/
#endif /* PROJECT_CONF_H_ */
/*---------------------------------------------------------------------------*/
Note: I want to update it in one of file as per some condition and then use the updated value in a different file.
First off, TEST_VALUE is a macro. You can read it but you can not write to it. It will also disappear at runtime.
What you really want is a global variable.
In the header put something like this:
#ifndef PROJECT_CONF_H_
#define PROJECT_CONF_H_
int g_TEST_VALUE; // Declaration
/*---------------------------------------------------------------------------*/
#endif /* PROJECT_CONF_H_ */
/*---------------------------------------------------------------------------*/
in your source put something like this:
#include "contiki.h"
#include <stdio.h> /* For printf() */
/*---------------------------------------------------------------------------*/
extern int g_TEST_VALUE = 1; // Definition
PROCESS(hello_world_process, "Hello world process");
AUTOSTART_PROCESSES(&hello_world_process);
static void update_project_conf_value(void)
{
printf("Original Value: %d\n",TEST_VALUE);
g_TEST_VALUE = 0;
printf("After update: %d\n",TEST_VALUE);
}
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(hello_world_process, ev, data)
{
PROCESS_BEGIN();
update_project_conf_value();
PROCESS_END();
}
/*---------------------------------------------------------------------------*/

ioctl call program compiling error

I want to call kernel module driver.ko ioctl from user space with c program. when compiling I got this error
header.h:13:38: error: expected expression before ‘char’
#define IOCTL_CMD _IORW(MAGIC_NO, 0, char *)
by definition I put the right arguments : _IORW(int type, int number, data_type)
main.c
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include "header.h"
int main()
{
int fd;
char * msg = "5";
fd = open(DEVICE_PATH, O_RDWR);
ioctl(fd, IOCTL_CMD, msg);
printf("ioctl executed\n");
close(fd);
return 0;
}
header.h
#include <linux/ioctl.h>
#include <linux/kdev_t.h> /* for MKDEV */
#define DEVICE_NAME "driver"
#define DEVICE_PATH "/dev/driver"
#define WRITE 0
static int major_no;
#define MAGIC_NO '4'
/*
* Set the message of the device driver
*/
#define IOCTL_CMD _IORW(MAGIC_NO, 0, char *)
The macro _IORW doesn't seem to exist in the Linux headers, try using _IOWR instead. Also I don't think you're use of char * is correct here. That would imply the last parameter to ioctl is the address of a char * variable, not a string.

Getting the saved instruction pointer address from a signal handler

My question is somewhat different from others that have asked about fault addresses. I'm trying to implement a horrible hack to determine, from a signal handler, whether the signal interrupted a syscall or ordinary user code by inspecting the code at the saved instruction pointer and comparing it against the possible syscall entry instructions for the host architecture it's running on. This is part of implementing correct POSIX thread cancellation that does not suffer from the race condition and resource leak described in my old question:
How are POSIX cancellation points supposed to behave?
If this approach is unreliable or otherwise wrong, I'd also like to hear reasons.
/* sigsegv.c */
/**
* This source file is used to print out a stack-trace when your program
* segfaults. It is relatively reliable and spot-on accurate.
*
* This code is in the public domain. Use it as you see fit, some credit
* would be appreciated, but is not a prerequisite for usage. Feedback
* on it's use would encourage further development and maintenance.
*
* Due to a bug in gcc-4.x.x you currently have to compile as C++ if you want
* demangling to work.
*
* Please note that it's been ported into my ULS library, thus the check for
* HAS_ULSLIB and the use of the sigsegv_outp macro based on that define.
*
* Author: Jaco Kroon <jaco#kroon.co.za>
*
* Copyright (C) 2005 - 2010 Jaco Kroon
*/
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
/* Bug in gcc prevents from using CPP_DEMANGLE in pure "C" */
#if !defined(__cplusplus) && !defined(NO_CPP_DEMANGLE)
#define NO_CPP_DEMANGLE
#endif
#include <memory.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <ucontext.h>
#include <dlfcn.h>
#ifndef NO_CPP_DEMANGLE
#include <cxxabi.h>
#ifdef __cplusplus
using __cxxabiv1::__cxa_demangle;
#endif
#endif
#ifdef HAS_ULSLIB
#include "uls/logger.h"
#define sigsegv_outp(x) sigsegv_outp(,gx)
#else
#define sigsegv_outp(x, ...) fprintf(stderr, x "\n", ##__VA_ARGS__)
#endif
#if defined(REG_RIP)
# define SIGSEGV_STACK_IA64
# define REGFORMAT "%016lx"
#elif defined(REG_EIP)
# define SIGSEGV_STACK_X86
# define REGFORMAT "%08x"
#else
# define SIGSEGV_STACK_GENERIC
# define REGFORMAT "%x"
#endif
static void signal_segv(int signum, siginfo_t* info, void*ptr) {
static const char *si_codes[3] = {"", "SEGV_MAPERR", "SEGV_ACCERR"};
int i, f = 0;
ucontext_t *ucontext = (ucontext_t*)ptr;
Dl_info dlinfo;
void **bp = 0;
void *ip = 0;
sigsegv_outp("Segmentation Fault!");
sigsegv_outp("info.si_signo = %d", signum);
sigsegv_outp("info.si_errno = %d", info->si_errno);
sigsegv_outp("info.si_code = %d (%s)", info->si_code, si_codes[info->si_code]);
sigsegv_outp("info.si_addr = %p", info->si_addr);
for(i = 0; i < NGREG; i++)
sigsegv_outp("reg[%02d] = 0x" REGFORMAT, i, ucontext->uc_mcontext.gregs[i]);
#ifndef SIGSEGV_NOSTACK
#if defined(SIGSEGV_STACK_IA64) || defined(SIGSEGV_STACK_X86)
#if defined(SIGSEGV_STACK_IA64)
ip = (void*)ucontext->uc_mcontext.gregs[REG_RIP];
bp = (void**)ucontext->uc_mcontext.gregs[REG_RBP];
#elif defined(SIGSEGV_STACK_X86)
ip = (void*)ucontext->uc_mcontext.gregs[REG_EIP];
bp = (void**)ucontext->uc_mcontext.gregs[REG_EBP];
#endif
sigsegv_outp("Stack trace:");
while(bp && ip) {
if(!dladdr(ip, &dlinfo))
break;
const char *symname = dlinfo.dli_sname;
#ifndef NO_CPP_DEMANGLE
int status;
char * tmp = __cxa_demangle(symname, NULL, 0, &status);
if (status == 0 && tmp)
symname = tmp;
#endif
sigsegv_outp("% 2d: %p <%s+%lu> (%s)",
++f,
ip,
symname,
(unsigned long)ip - (unsigned long)dlinfo.dli_saddr,
dlinfo.dli_fname);
#ifndef NO_CPP_DEMANGLE
if (tmp)
free(tmp);
#endif
if(dlinfo.dli_sname && !strcmp(dlinfo.dli_sname, "main"))
break;
ip = bp[1];
bp = (void**)bp[0];
}
#else
sigsegv_outp("Stack trace (non-dedicated):");
sz = backtrace(bt, 20);
strings = backtrace_symbols(bt, sz);
for(i = 0; i < sz; ++i)
sigsegv_outp("%s", strings[i]);
#endif
sigsegv_outp("End of stack trace.");
#else
sigsegv_outp("Not printing stack strace.");
#endif
_exit (-1);
}
static void __attribute__((constructor)) setup_sigsegv() {
struct sigaction action;
memset(&action, 0, sizeof(action));
action.sa_sigaction = signal_segv;
action.sa_flags = SA_SIGINFO;
if(sigaction(SIGSEGV, &action, NULL) < 0)
perror("sigaction");
}
$ g++ -fPIC -shared -o libsigsegv.so -ldl sigsegv
$ export LD_PRELOAD=/path/to/libsigsegv.so
I found this code on a LUG. Couldn't get to the page to point the URL here, so pasted the whole code. This code prints a small stack trace when SIGSEGV occurs. Not sure if there is some other way that does not use ucontext_t.

Resources