Crash工具笔记 (1)—— “current context”

成功启动crash会话后,会有一个task被指定为current context。因为有一些命令是context-sensitive,也即这些命令的运行会依赖于current context,所以知道当前的current context就很重要。

选择current context的标准:

The task that was running when die() was called.
The task that was running when panic() was called.
The task that was running when an ALT-SYSRQ-c keyboard interrupt was received.
The task that was running when the character "c" was echoed to /proc/sysrq-trigger. 



执行set命令显示当前current context

crash> set
    PID: 2366
COMMAND: "crash"
   TASK: ffff88001ae60000  [THREAD_INFO: ffff88001c1f0000]
    CPU: 0

也可利用set命令改变当前current context

crash> set 1
    PID: 1
COMMAND: "systemd"
   TASK: ffff88001dfd8000  [THREAD_INFO: ffff88001dfe0000]
    CPU: 0




/dev/mem is a character device file that is an image of the main memory of the computer. It may be used, for example, to examine (and even patch) the system. Byte addresses in /dev/mem are interpreted as physical memory addresses. References to nonexistent locations cause errors to be returned.

The file /dev/kmem is the same as /dev/mem, except that the kernel virtual memory rather than physical memory is accessed.

/dev/port is similar to /dev/mem, but the I/O ports are accessed.


SystemTap 笔记 (8)—— typecasting

当指针是一个void *类型,或是保存为整数后,可以使用cast运算符指定指针的数据类型:

@cast(p, "type_name"[, "module"])->member

可选的module参数用来指定从哪里得到type_name(The optional module tells the translator where to look for information about that type. Multiple modules may be specified as a list with : separators. If the module is not specified, it will default either to the probe module for dwarf probes, or to “kernel” for functions and all other probes types.)。


The translator can create its own module with type information from a header surrounded by angle brackets, in case normal debuginfo is not available. For kernel headers, prefix it with “kernel” to use the appropriate build system. All other headers are build with default GCC parameters into a user module. Multiple headers may be specified in sequence to resolve a codependency.

@cast(tv, “timeval”, “<sys/time.h>”)->tvsec
@cast(task, “task
struct”, “kernel<linux/sched.h>”)->tgid
@cast(task, “taskstruct”, “kernel<linux/sched.h><linux/fsstruct.h>”)->fs->umask


# stap -e 'probe kernel.function("do_dentry_open") {printf("%d\n", $f->f_flags); exit(); }'


# stap -e 'probe kernel.function("do_dentry_open") {printf("%d\n", @cast($f, "file", "kernel<linux/fs.h>" )->f_flags); exit(); }'

SystemTap 笔记 (7)—— target variable (2)

SystemTap可以为target variable生成一系列可打印的字符串:


Expands to a character string that is equivalent to sprintf(“parm1=%x … parmN=%x var1=%x … varN=%x”, parm1, …, parmN, var1, …, varN) for each variable in scope at the probe point. Some values may be printed as “=?” if their run-time location cannot be found.


Expands to a subset of $$vars containing only the local variables.


Expands to a subset of $$vars containing only the function parameters.


Is available in return probes only. It expands to a string that is equivalent to sprintf(“return=%x”, $return) if the probed function has a return value, or else an empty string.


# stap -e 'probe kernel.function("do_dentry_open") {printf("%s\n", $$vars); exit(); }'
f=0xffff880022ec6080 open=0x0 cred=0xffff880030d483c0 empty_fops={...} inode=? error=?
# stap -e 'probe kernel.function("do_dentry_open") {printf("%s\n", $$parms); exit(); }'
f=0xffff880030d453c0 open=0x0 cred=0xffff880030d483c0
# stap -e 'probe kernel.function("do_dentry_open") {printf("%s\n", $$locals); exit(); }'
empty_fops={...} inode=? error=?


# stap -e 'probe kernel.function("do_dentry_open") {printf("%s\n", $$parms$); exit(); }'
f={.f_u={...}, .f_path={...}, .f_inode=0x0, .f_op=0x0, .f_lock={...}, .f_count={...}, .f_flags=32768, .f_mode=0, .f_pos=0, .f_owner={...}, .f_cred=0xffff880030d483c0, .f_ra={...}, .f_version=0, .f_security=0xffff880012982b80, .private_data=0x0, .f_ep_links={...}, .f_tfile_llink={...}, .f_mapping=0x0} open=<function>:0x0 cred={.usage={...}, .uid={...}, .gid={...}, .suid={...}, .sgid={...}, .euid={...}, .egid={...}, .fsuid={...}, .fsgid={...}, .securebits=0, .cap_inheritable={...}, .cap_permitted={...}, .cap
# stap -e 'probe kernel.function("do_dentry_open") {printf("%s\n", $$parms$$); exit(); }'
f={.f_u={.fu_llist={.next=0x0}, .fu_rcuhead={.next=0x0, .func=0x0}}, .f_path={.mnt=0xffff8800337510e0, .dentry=0xffff8800318b82d8}, .f_inode=0x0, .f_op=0x0, .f_lock={<union>={.rlock={.raw_lock={.head_tail=0, <class>={.tickets={.head=0, .tail=0}, .owner=0}}}}}, .f_count={.counter=1}, .f_flags=32768, .f_mode=0, .f_pos=0, .f_owner={.lock={.raw_lock={.lock=1048576, .write=1048576}}, .pid=0x0, .pid_type=0, .uid={.val=0}, .euid={.val=0}, .signum=0}, .f_cred=0xffff880030d89300, .f_ra={.start=0, .size=0, .async_si


Linux kernel 笔记 (44)——使用字符设备

Linux kernel 使用 cdev结构体代表字符设备(char device),定义在<linux/cdev.h>

#include <linux/kobject.h>
#include <linux/kdev_t.h>
#include <linux/list.h>

struct file_operations;
struct inode;
struct module;

struct cdev {
    struct kobject kobj;
    struct module *owner;
    const struct file_operations *ops;
    struct list_head list;
    dev_t dev;
    unsigned int count;

void cdev_init(struct cdev *, const struct file_operations *);

struct cdev *cdev_alloc(void);

void cdev_put(struct cdev *p);

int cdev_add(struct cdev *, dev_t, unsigned);

void cdev_del(struct cdev *);

void cd_forget(struct inode *);



struct cdev *my_cdev = cdev_alloc();
my_cdev->ops = &my_fops;
my_cdev->owner = THIS_MODULE;


struct scull_dev {
    struct cdev cdev; /* Char device structure */

static void scull_setup_cdev(struct scull_dev *dev, int index)
    int err, devno = MKDEV(scull_major, scull_minor + index);
    cdev_init(&dev->cdev, &scull_fops);
    dev->cdev.owner = THIS_MODULE;
    dev->cdev.ops = &scull_fops;



 * cdev_add() - add a char device to the system
 * @p: the cdev structure for the device
 * @dev: the first device number for which this device is responsible
 * @count: the number of consecutive minor numbers corresponding to this
 *         device
 * cdev_add() adds the device represented by @p to the system, making it
 * live immediately.  A negative error code is returned on failure.
int cdev_add(struct cdev *p, dev_t dev, unsigned count)
    int error;

    p->dev = dev;
    p->count = count;

    error = kobj_map(cdev_map, dev, count, NULL,
             exact_match, exact_lock, p);
    if (error)
        return error;


    return 0;

要注意count指定的是连续的minor number数。


 * cdev_del() - remove a cdev from the system
 * @p: the cdev structure to be removed
 * cdev_del() removes @p from the system, possibly freeing the structure
 * itself.
void cdev_del(struct cdev *p)
    cdev_unmap(p->dev, p->count);