To install package from Arch Linux user repository, you should use a common user account, not a root
. Take setting up trace-cmd as an example:
$ git clone https://aur.archlinux.org/trace-cmd.git
$ cd trace-cmd
$ makepkg -si
To install package from Arch Linux user repository, you should use a common user account, not a root
. Take setting up trace-cmd as an example:
$ git clone https://aur.archlinux.org/trace-cmd.git
$ cd trace-cmd
$ makepkg -si
Recently, after I upgrade gcc
on my Arch Linux
, I find it has enabled “--enable-default-pie
” option by default:
$ gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-pc-linux-gnu/7.1.1/lto-wrapper
Target: x86_64-pc-linux-gnu
Configured with: /build/gcc/src/gcc/configure --prefix=/usr --libdir=/usr/lib --libexecdir=/usr/lib --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=https://bugs.archlinux.org/ --enable-languages=c,c++,ada,fortran,go,lto,objc,obj-c++ --enable-shared --enable-threads=posix --enable-libmpx --with-system-zlib --with-isl --enable-__cxa_atexit --disable-libunwind-exceptions --enable-clocale=gnu --disable-libstdcxx-pch --disable-libssp --enable-gnu-unique-object --enable-linker-build-id --enable-lto --enable-plugin --enable-install-libiberty --with-linker-hash-style=gnu --enable-gnu-indirect-function --disable-multilib --disable-werror --enable-checking=release --enable-default-pie --enable-default-ssp
Thread model: posix
gcc version 7.1.1 20170630 (GCC)
One consequence of this enhancement is you should rebuild the static libraries which you projects depend on, otherwise you may counter totally confused link errors like this:
relocation R_X86_64_32S against `.text’ can not be used when making a shared object; recompile with -fPIC
A caveat you must pay attention to is if your static library has assembly code object which is not position independent, you must specify “-no-pie
” option during link stage of generating final executable binary. This issue let me spend half day to debug, so it is a really good habit to check critical packages’ change log, such as your compiler.
Reference:
PIE.
Although many Open Source projects don’t require you publish the modifications of them, I still propose you should make the changes open. The reasons are as following:
(1) For other people: the out-of-box Open Source projects save your time and money, and you get benefit from them. You should not only take, but also need to give! Only if everyone shares his code, document, or whatever related, the Open Source projects can grow up healthy.
(2) For yourself: You release your code can actually make you “richer”. With more and more people use your code, more and more bugs will be found, and associated patches would also be submitted simultaneously. In fact, you can leverage the whole community to help test your code and it saves your bucks which could be used to employ QA/testing engineers. The other invisible gain is the contributions can boost both you and your employer’s reputation, and it will definitely be a big fortune in your future life!
Based on the above points, don’t be hesitate to share your changes. You just need to know give more, gain more!
If you want to use ANTLR C runtime library, you should pay attention that it will be compiled to 32-bit
library by default even in 64-bit
platform:
# ./configure
......
# make
make all-am
make[1]: Entering directory '/root/Project/libantlr3c-3.4'
/bin/sh ./libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -Iinclude -m32 -O2 -Wall -MT antlr3baserecognizer.lo -MD -MP -MF .deps/antlr3baserecognizer.Tpo -c -o antlr3baserecognizer.lo `test -f 'src/antlr3baserecognizer.c' || echo './'`src/antlr3baserecognizer.c
libtool: compile: gcc -DHAVE_CONFIG_H -I. -Iinclude -m32 -O2 -Wall -MT antlr3baserecognizer.lo -MD -MP -MF .deps/antlr3baserecognizer.Tpo -c src/antlr3baserecognizer.c -fPIC -DPIC -o .libs/antlr3baserecognizer.o
In file included from /usr/include/features.h:434:0,
from /usr/include/bits/libc-header-start.h:33,
from /usr/include/stdio.h:28,
from include/antlr3defs.h:248,
from include/antlr3baserecognizer.h:39,
from src/antlr3baserecognizer.c:9:
/usr/include/gnu/stubs.h:7:11: fatal error: gnu/stubs-32.h: No such file or directory
# include <gnu/stubs-32.h>
^~~~~~~~~~~~~~~~
compilation terminated.
make[1]: *** [Makefile:449: antlr3baserecognizer.lo] Error 1
make[1]: Leaving directory '/root/Project/libantlr3c-3.4'
make: *** [Makefile:308: all] Error 2
In order to build 64-bit
library, you should specify --enable-64bit
option during configure
stage:
./configure --enable-64bit
Then it will be generated to 64-bit
library.
The bcc
gives a simple Hello World program analysis, but I want to give a more detailed anatomy of it:
from bcc import BPF
BPF(text='int kprobe__sys_clone(void *ctx) { bpf_trace_printk("Hello, World!\\n"); return 0; }').trace_print()
(1)
from bcc import BPF
bcc
is a package
, and it will be installed in Python
‘s site-packages
directory. Take my server as an example:
>>> import bcc
>>> bcc.__path__
['/usr/lib/python3.6/site-packages/bcc']
BPF
is a class defined in __init__.py
file of bcc
:
......
class BPF(object):
# From bpf_prog_type in uapi/linux/bpf.h
SOCKET_FILTER = 1
KPROBE = 2
......
(2) Divide
BPF(text='int kprobe__sys_clone(void *ctx) { bpf_trace_printk("Hello, World!\\n"); return 0; }').trace_print()
into 2
parts:
BPF(text='int kprobe__sys_clone(void *ctx) { bpf_trace_printk("Hello, World!\\n"); return 0; }')
and
trace_print()
a)
BPF(text='int kprobe__sys_clone(void *ctx) { bpf_trace_printk("Hello, World!\\n"); return 0; }')
This statement will create a BPF
object, and the code is simplified as following:
......
from .libbcc import lib, _CB_TYPE, bcc_symbol, _SYM_CB_TYPE
......
class BPF(object):
......
def __init__(self, src_file="", hdr_file="", text=None, cb=None, debug=0,
cflags=[], usdt_contexts=[]):
......
if text:
self.module = lib.bpf_module_create_c_from_string(text.encode("ascii"),
self.debug, cflags_array, len(cflags_array))
else:
......
self._trace_autoload()
Check libbcc.py:
lib = ct.CDLL("libbcc.so.0", use_errno=True)
We can see lib
module is indeed libbcc dynamic library, and bpf_module_create_c_from_string is implemented as this:
void * bpf_module_create_c_from_string(const char *text, unsigned flags, const char *cflags[], int ncflags) {
auto mod = new ebpf::BPFModule(flags);
if (mod->load_string(text, cflags, ncflags) != 0) {
delete mod;
return nullptr;
}
return mod;
}
We won’t delve it too much, and just know it returns a ebpf
module is enough.
For self._trace_autoload()
part, we can check _trace_autoload
method definition:
def _trace_autoload(self):
for i in range(0, lib.bpf_num_functions(self.module)):
func_name = str(lib.bpf_function_name(self.module, i).decode())
if func_name.startswith("kprobe__"):
fn = self.load_func(func_name, BPF.KPROBE)
self.attach_kprobe(event=fn.name[8:], fn_name=fn.name)
elif func_name.startswith("kretprobe__"):
fn = self.load_func(func_name, BPF.KPROBE)
self.attach_kretprobe(event=fn.name[11:], fn_name=fn.name)
elif func_name.startswith("tracepoint__"):
fn = self.load_func(func_name, BPF.TRACEPOINT)
tp = fn.name[len("tracepoint__"):].replace("__", ":")
self.attach_tracepoint(tp=tp, fn_name=fn.name)
Based on above code, we can see bcc
now supports kprobe
, kretprobe
and tracepoint
. For Hello World
example, it actually execute attach_kprobe
method:
def attach_kprobe(self, event="", fn_name="", event_re="",
pid=-1, cpu=0, group_fd=-1):
......
event = str(event)
self._check_probe_quota(1)
fn = self.load_func(fn_name, BPF.KPROBE)
ev_name = "p_" + event.replace("+", "_").replace(".", "_")
res = lib.bpf_attach_kprobe(fn.fd, 0, ev_name.encode("ascii"),
event.encode("ascii"), pid, cpu, group_fd,
self._reader_cb_impl, ct.cast(id(self), ct.py_object))
res = ct.cast(res, ct.c_void_p)
......
self._add_kprobe(ev_name, res)
return self
Finally, it will call libbcc
‘s bpf_attach_kprobe
function. Until now, the kprobe
is attached successfully, and attach_kprobe
will return a BPF
object.
(b)
BPF(...).trace_print()
The trace_print
method is not too hard:
def trace_print(self, fmt=None):
......
try:
while True:
if fmt:
fields = self.trace_fields(nonblocking=False)
if not fields: continue
line = fmt.format(*fields)
else:
line = self.trace_readline(nonblocking=False)
print(line)
sys.stdout.flush()
except KeyboardInterrupt:
exit()
For fmt=None
case, it just calls trace_readline()
, which read from trace pipe, and prints it on the stdout
:
print(line)
sys.stdout.flush()
That’s all, and hope you enjoy bcc
and ebpf
!