I have configure.in script. I want to invoke configure ( after autoheader && autoconf ) and see value of PAGE_SHIFT macro from system header page_types.h. Something like this:
checking PAGE_SHIFT... 12
I've tried those:
1.
AC_CHECK_DECL([PAGE_SHIFT],[HAVE_PAGE_SHIFT=$PAGE_SHIFT],[],
[#include <linux/module.h>])
AC_MSG_NOTICE([${HAVE_PAGE_SHIFT}])
Result: macro PAGE_SHIFT was detected, but haven't been printed
checking whether PAGE_SHIFT is declared... yes
configure:
2.
HAVE_PAGE_SHIFT="Unknown"
AC_MSG_CHECKING([PAGE_SHIFT])
AC_COMPILE_IFELSE(
[
AC_LANG_PROGRAM([
#include <linux/module.h>
#include <stdio.h>
],
[
printf("%d\n", PAGE_SHIFT);
])],
[HAVE_PAGE_SHIFT="$PAGE_SHIFT"], [])
AC_MSG_RESULT([${HAVE_PAGE_SHIFT}])
Result: doesn't work
checking PAGE_SHIFT...
3.
AC_MSG_CHECKING(['PAGE_SHIFT' value])
AC_RUN_IFELSE(
[
#include <linux/module.h>
#include <stdio.h>
int
main ()
{
printf("%d\n", PAGE_SHIFT);
return 0;
}
]
)
Result: works, but can't be used with cross-compile
checking 'PAGE_SHIFT' value... 12
method was suggested by Brett Hale
Autoconf will generate something like this:
#include <linux/module.h>
static long int longval () { return PAGE_SHIFT; }
static unsigned long int ulongval () { return PAGE_SHIFT; }
#include <stdio.h>
#include <stdlib.h>
Result: doesn't work with kernel headers
In file included from /usr/include/stdlib.h:314:0,
from conftest.c:125:
/usr/include/x86_64-linux-gnu/sys/types.h:44:18: error: conflicting types for 'loff_t'
typedef __loff_t loff_t;
^
In file included from /lib/modules/4.2.0-18-generic/build/arch/x86/include/asm/page_types.h:5:0,
from [...],
from conftest.c:121:
/lib/modules/4.2.0-18-generic/build/include/linux/types.h:45:26: note: previous declaration of 'loff_t' was here
typedef __kernel_loff_t loff_t;
Autoconf version: autoconf (GNU Autoconf) 2.69
I would recommend using the AC_COMPUTE_INT macro. e.g.,
AC_MSG_CHECKING(['PAGE_SHIFT' value])
AC_COMPUTE_INT([PAGE_SHIFT_VAL], [PAGE_SHIFT], [[#include <linux/module.h>]],
AC_MSG_FAILURE([linux/module.h: could not determine 'PAGE_SHIFT' value]))
AC_MSG_RESULT([$PAGE_SHIFT_VAL])
Alternatively, you can replace the FAILURE macro with PAGE_SHIFT_VAL=0 and test that value for (0) if the error is recoverable.
Note that there's nothing magical about the variable name PAGE_SHIFT_VAL, in this context; you can use another name. You still need the AC_SUBST if you want this value substituted in generated files, like config.h, or those listed in AC_CONFIG_FILES.
Related
I wrote a simple program to attach to execve system call with a kprobe, but I am unable to see the relevant output.
Here is my one.c (BPF program):
#include <errno.h>
#include <bpf/bpf.h>
#include <stdio.h>
#include <string.h>
#include "bpf_load.h"
#include "bpf_util.h"
#include "libbpf.h"
#define SEC(NAME) __attribute__((section(NAME), used))
SEC("kprobe/execve")
int bpf_prog1(struct pt_regs *ctx)
{
char m[]="hello world";
bpf_trace_printk(m,sizeof(m));
return 0;
}
char _license[] SEC("license") = "GPL";
bpf_load.c (user space loader):
#include "bpf_load.h"
#include <stdio.h>
#include <linux/bpf.h>
#include <sys/resource.h>
int main(int argc, char **argv) {
if (load_bpf_file("one.o")) {
printf("%s", bpf_log_buf);
return 1;
}
return 0;
}
And the Makefile:
CLANG = clang
EXECABLE = monitor-exec
BPFCODE = one
BPFTOOLS = /kernel-src/samples/bpf
BPFLOADER = $(BPFTOOLS)/bpf_load.c
INCLUDE += -I/kernel-src/samples/bpf
INCLUDE += -I/kernel-src/tools/lib
CCINCLUDE += -I/kernel-src/tools/testing/selftests/bpf
CCINCLUDE += -I/kernel-src/tools/lib/bpf
CCINCLUDE += ${INCLUDE}
LOADINCLUDE += -I/kernel-src/tools/include
LOADINCLUDE += -I/kernel-src/tools/perf
LOADINCLUDE += ${INCLUDE}
LIBRARY_PATH = -L/usr/local/lib64
BPFSO = -lbpf
.PHONY: clean bpfload build
clean:
rm -f *.o *.so $(EXECABLE)
build: ${BPFCODE.c} ${BPFLOADER}
$(CLANG) -O2 -DHAVE_ATTR_TEST=0 -target bpf -c $(BPFCODE:=.c) $(CCINCLUDE) -o ${BPFCODE:=.o}
bpfload: build
clang -o $(EXECABLE) -DHAVE_ATTR_TEST=0 -lelf $(LOADINCLUDE) $(LIBRARY_PATH) $(BPFSO) \
$(BPFLOADER) loader.c
$(EXECABLE): bpfload
.DEFAULT_GOAL := $(EXECABLE)
As of now I don't get any errors from the Makefile.
I am getting the following output when I execute ./monitor-exec
invalid relo for insn[6].code 0x85
bpf_load_program() err=22
last insn is not an exit or jmp
processed 0 insns (limit 1000000) max_states_per_insn 0 total_states 0 peak_states 0 mark_read 0
last insn is not an exit or jmp
processed 0 insns (limit 1000000) max_states_per_insn 0 total_states 0 peak_states 0 mark_read 0
I am unable to understand what I am doing wrong. I am just attaching a kprobe and that should print hello world when that system call occurs.
In your eBPF program:
#include <errno.h>
#include <bpf/bpf.h>
#include <stdio.h>
#include <string.h>
#include "bpf_load.h"
#include "bpf_util.h"
#include "libbpf.h"
#define SEC(NAME) __attribute__((section(NAME), used))
SEC("kprobe/execve")
int bpf_prog1(struct pt_regs *ctx)
{
char m[]="hello world";
bpf_trace_printk(m,sizeof(m));
return 0;
}
You use bpf_trace_printk() correctly (although you might want to add a \n at the end of your message or your output will be messy), but it turns out none of the files you include contains the definition for this helper.
bpf_trace_printk() is compiled as part of the kernel and won't ever be compiled into your BPF object file. When trying to load your program, the function load_bpf_file() does a relocation step where it places the number associated to bpf_trace_printk() (in user API) in the relevant instruction of the eBPF bytecode.
But it needs to find this number somewhere. It is defined in header linux/bpf.h (pulled from several of your includes) as FN(trace_printk) (some macro magic going on), resulting de facto in a #define BPF_FUNC_trace_prink 6. But you need to tell your loading function that it corresponds to the bpf_trace_prink() you're calling!
Two solutions:
Manually declare it:
static int (*bpf_trace_printk)(const char *fmt, int fmt_size, ...) =
(void *) BPF_FUNC_trace_printk;
Or add a header that contains it, e.g. tools/lib/bpf/bpf_helpers.h in kernel repo. In your case:
#include <bpf/bpf_helpers.h>
(Note that this header is generated when compiling libbpf, it is not present in the repository by default.)
Is there a better way to write an autoconf test for a missing prototype than by setting CFLAGS to "-Werror -Wimplicit-function-declaration" ?
Specifically, I'm trying to determine if I need to provide my own pwrite(2)
and pread(2). If the environment is strict, pread/pwrite are not defined.
here's what I have now, which works:
AC_INIT([pwrite],[0.0.0],[none],[nothing],[nowhere])
AC_CONFIG_HEADERS([config.h])
old_CFLAGS=$CFLAGS
CFLAGS="-Werror $CFLAGS"
AC_COMPILE_IFELSE([AC_LANG_PROGRAM(,[
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
int main(int argc, char **argv) {
int ret = pwrite(99, "blah", 1, 0);
return 0;
} ]) ],
AC_MSG_RESULT([using system pwrite prototype])
AC_DEFINE(HAVE_PWRITE, 1, [pwrite protoype exists]),
AC_MSG_RESULT([no pwrite protoype. using our own])
)
CFLAGS=$old_CFLAGS
AC_OUTPUT()
When I do this, configure CFLAGS=-std=c99 will indeed detect that pwrite is declared implicitly, and configure alone will find a pwrite prototype in unistd.h. However, mucking with CFLAGS inside configure doesn't seem like the "autoconf-y" way to do this.
If you look at the source of the autoconf macros you find that a lot of them save and restore CFLAGS. You need to be very careful using -Werror though, as you might get incorrect results. e.g., if argc, argv are unused - as is ret - a warning (see: -Wunused* flags) will be interpreted as pwrite being unavailable.
Assuming <unistd.h> compiles without warning-as-errors, which it should:
<save CFLAGS>
CFLAGS="$CFLAGS -Werror=implicit-function-declaration"
AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
[[#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif]],
[[(void) pwrite(99, "blah", 1, 0);]])],
<action-on-success>,
<action-on-fail>)
<restore CFLAGS>
The (void) cast is probably unnecessary - it's for crazy-strict warnings that will probably not be silent even for system headers, but doesn't hurt. It might be worth looking at the _XOPEN_SOURCE macro value - e.g., setting _XOPEN_SOURCE in this test and the library code.
Saving/restoring CFLAGS is acceptable but for this particular purpose, AC_CHECK_DECLS turns out to be precisely what I was looking for, and furthermore does not have any problems with super-picky compilers or trying to figure out what is the Portland Group compiler equivalent to -Werror-implicit-function-declaration.
AC_INIT([pwrite],[0.0.0],[none],[nothing],[nowhere])
AC_CONFIG_HEADERS([config.h])
AC_CHECK_HEADERS([unistd.h])
AC_CHECK_DECLS([pwrite])
AC_OUTPUT()
and then in my code I do have to check the result a little differently:
#if (HAVE_DECL_PWRITE == 0)
... implement our own pwrite
#endif
Why NTDDI_VERSION macro changes its value from cpp it includes to ntdddisk.h ?
I am using Visual Studio 2012 with cumulative update 4, and building on Windows 7 x64.
In one CPP i need to call new IOCTL_ .. for WIN 8.
In the CPP there is #include
ntdddisk.h defines the new IOCTL_ for WIN 8 under the guarded condition:
#if (NTDDI_VERSION >= NTDDI_WIN8)
...
#endif
Inside that cpp the NTDDI_VERSION macro has value NTDDI_WIN8 (as expected result from include sdkddkver.h and compilation with /D_WIN32_WINNT=0x0602)
However, in ntdddisk.h the value for NTDDI_VERSION macro has value < NTDDI_VISTA, that is, less than NTDDI_WIN8
Compilation fails with error
error C2065: 'IOCTL_..' : undeclared identifier
Looks like a bug unless i miss something else. Thoughts?
Details are:
In the CPP file there are these includes
#pragma once
// Needed for new IOCTL_ for WIN 8
#include <sdkddkver.h>
#include <windows.h>
// Check NTDDI_VERSION ...
#if (NTDDI_VERSION >= NTDDI_WIN8)
// Value is NTDDI_WIN8 as expected
// #include <TROUBLE.h>
#endif
#pragma pack(8)
#include <ntdddisk.h>
#include <ntddscsi.h>
#include <lm.h>
#include <objbase.h>
/*=== IMPORTANT: this struct needs to have 8-byte packing ===*/
typedef struct _SCSI_PASS_THROUGH_WITH_BUFFERS {
SCSI_PASS_THROUGH spt;
ULONG Filler; // realign buffers to double word boundary
UCHAR SenseBuf[32];
UCHAR DataBuf[512];
} SCSI_PASS_THROUGH_WITH_BUFFERS;
#pragma pack()
Compilation with CL has these parameters including with -D_WIN32_WINNT=0x0602
cl -nologo #COMPL.TMP /Fo..\\..\\..\\optimized\\obj\\x86\\CPP.obj CPP.cpp
COMPL.TMP contains
/I*** application-headers ***
-D_AFXDLL -c -D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE -DBTREEDB -O2 -Ox -MD -Zi -DNT_CLIENT -DWIN32 -D"_CONSOLE" -D_THREADS -D_OPSYS_TYPE=DS_WINNT -DPSAPI_VERSION=1 -D_WIN32_WINNT=0x0602 -TP -DMBCS=1 -D_LONG_LONG=1 -D_DSM_VLK_BTREE -DDSM_WIDECHAR -D_UNICODE -DUNICODE -DUSE_XML=1 -DXMLUTIL_EXPORTS=1 -DUSE_XERCES_2_8=1 -DPEGASUS_PLATFORM_WIN32_IX86_MSVC=1 -DPEGASUS_USE_EXPERIMENTAL_INTERFACES -Zp1 -D_DSM_LONG_NAME -W3 -EHsc -GF
The problem isn't with the _WIN32_WINNT or NTDDI_VERSION macros.
The problem is that windows.h indirectly includes winioctl.h which has the following curious couple of lines about halfway through:
#ifndef _NTDDDISK_H_
#define _NTDDDISK_H_
Unsurprisingly, ntdddisk.h starts with those very same lines and therefore is effectively not included at all.
I couldn't easily come up with a combination or ordering of headers that would work around this problem - I think it's something that MS really needs to fix.
However, the following terrible workaround (that I really don't suggest, unless you can't get any help from MS) seemed to get the compiler to actually process ntdddisk.h:
#define _NTDDDISK_H_
#include <windows.h>
#undef _NTDDDISK_H_
But, I suspect there may be other problems that might pop up as a result of this hack - so if you decide to use it, please test carefully.
I am not sure that this is what i need, but the compilation worked after inserting
#define _NTDDDISK_H_
#include <windows.h>
...
#undef _NTDDDISK_H_
#include <ntdddisk.h>
Thanks for suggestion.
I have a GNU/Linux application with uses a number of shared memory objects. It could, potentially, be run a number of times on the same system. To keep things tidy, I first create a directory in /dev/shm for each of the set of shared memory objects.
The problem is that on newer GNU/Linux distributions, I no longer seem to be able create these in a sub-directory of /dev/shm.
The following is a minimal C program with illustrates what I'm talking about:
/*****************************************************************************
* shm_minimal.c
*
* Test shm_open()
*
* Expect to create shared memory file in:
* /dev/shm/
* └── my_dir
* └── shm_name
*
* NOTE: Only visible on filesystem during execution. I try to be nice, and
* clean up after myself.
*
* Compile with:
* $ gcc -lrt shm_minimal.c -o shm_minimal
*
******************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
int main(int argc, const char* argv[]) {
int shm_fd = -1;
char* shm_dir = "/dev/shm/my_dir";
char* shm_file = "/my_dir/shm_name"; /* does NOT work */
//char* shm_file = "/my_dir_shm_name"; /* works */
// Create directory in /dev/shm
mkdir(shm_dir, 0777);
// make shared memory segment
shm_fd = shm_open(shm_file, O_RDWR | O_CREAT, 0600);
if (-1 == shm_fd) {
switch (errno) {
case EINVAL:
/* Confirmed on:
* kernel v3.14, GNU libc v2.19 (ArchLinux)
* kernel v3.13, GNU libc v2.19 (Ubuntu 14.04 Beta 2)
*/
perror("FAIL - EINVAL");
return 1;
default:
printf("Some other problem not being tested\n");
return 2;
}
} else {
/* Confirmed on:
* kernel v3.8, GNU libc v2.17 (Mint 15)
* kernel v3.2, GNU libc v2.15 (Xubuntu 12.04 LTS)
* kernel v3.1, GNU libc v2.13 (Debian 6.0)
* kernel v2.6.32, GNU libc v2.12 (RHEL 6.4)
*/
printf("Success !!!\n");
}
// clean up
close(shm_fd);
shm_unlink(shm_file);
rmdir(shm_dir);
return 0;
}
/* vi: set ts=2 sw=2 ai expandtab:
*/
When I run this program on a fairly new distribution, the call to shm_open() returns -1, and errno is set to EINVAL. However, when I run on something a little older, it creates the shared memory object in /dev/shm/my_dir as expected.
For the larger application, the solution is simple. I can use a common prefix instead of a directory.
If you could help enlighten me to this apparent change in behavior it would be very helpful. I suspect someone else out there might be trying to do something similar.
So it turns out the issue stems from how GNU libc validates the shared memory name. Specifically, the shared memory object MUST now be at the root of the shmfs mount point.
This was changed in glibc git commit b20de2c3d9 as the result of bug BZ #16274.
Specifically, the change is the line:
if (name[0] == '\0' || namelen > NAME_MAX || strchr (name, '/') != NULL)
Which now disallows '/' from anywhere in the filename (not counting leading '/')
If you have a third party tool that was broken by this shm_open change, a brilliant coworker found a workaround : preload a library that overrides the shm_open call and swaps slashes for underscores. It does the same for shm_unlink as well, so the application can properly free shared memory when needed.
deslash_shm.cc :
#include <dlfcn.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <algorithm>
#include <string>
// function used in place of the standard shm_open() function
extern "C" int shm_open(const char *name, int oflag, mode_t mode)
{
// keep a function pointer to the real shm_open() function
static int (*real_open)(const char *, int, mode_t) = NULL;
// the first time in, ask the dynamic linker to find the real shm_open() function
if (!real_open) real_open = (int (*)(const char *, int, mode_t)) dlsym(RTLD_NEXT,"shm_open");
// take the name we were given and replace all slashes with underscores instead
std::string n = name;
std::replace(n.begin(), n.end(), '/', '_');
// call the real open function with the patched path name
return real_open(n.c_str(), oflag, mode);
}
// function used in place of the standard shm_unlink() function
extern "C" int shm_unlink(const char *name)
{
// keep a function pointer to the real shm_unlink() function
static int (*real_unlink)(const char *) = NULL;
// the first time in, ask the dynamic linker to find the real shm_unlink() function
if (!real_unlink) real_unlink = (int (*)(const char *)) dlsym(RTLD_NEXT, "shm_unlink");
// take the name we were given and replace all slashes with underscores instead
std::string n = name;
std::replace(n.begin(), n.end(), '/', '_');
// call the real unlink function with the patched path name
return real_unlink(n.c_str());
}
To compile this file:
c++ -fPIC -shared -o deslash_shm.so deslash_shm.cc -ldl
And preload it before starting a process that tries to use non-standard slash characters in shm_open:
in bash:
export LD_PRELOAD=/path/to/deslash_shm.so
in tcsh:
setenv LD_PRELOAD /path/to/deslash_shm.so
I want to create a file and map it into memory. I think that my code will work but when I run it I'm getting a "bus error". I searched google but I'm not sure how to fix the problem. Here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/mman.h>
#include <string.h>
int main(void)
{
int file_fd,page_size;
char buffer[10]="perfect";
char *map;
file_fd=open("/tmp/test.txt",O_RDWR | O_CREAT | O_TRUNC ,(mode_t)0600);
if(file_fd == -1)
{
perror("open");
return 2;
}
page_size = getpagesize();
map = mmap(0,page_size,PROT_READ | PROT_WRITE,MAP_SHARED,file_fd,page_size);
if(map == MAP_FAILED)
{
perror("mmap");
return 3;
}
strcpy(map, buffer);
munmap(map, page_size);
close(file_fd);
return 0;
}
You are creating a new zero sized file, you can't extend the file size with mmap. You'll get a bus error when you try to write outside the content of the file.
Use e.g. fallocate() on the file descriptor to allocate room in the file.
Note that you're also passing the page_size as the offset to mmap, which doesn't seem to make much sense in your example, you'll have to first extend the file to pagesize + strlen(buffer) + 1 if you want to write buf at that location. More likely you want to start at the beginning of the file, so pass 0 as the last argument to mmap.