Kernel-4.18.0-80.el8_gdbmacros

This file contains a few gdb macros (user defined commands) to extract

useful information from kernel crashdump (kdump) like stack traces of

all the processes or a particular process and trapinfo.

These macros can be used by copying this file in .gdbinit (put in home

directory or current directory) or by invoking gdb command with

–command= option

Credits:

Alexander Nyberg alexn@telia.com

V Srivatsa vatsa@in.ibm.com

Maneesh Soni maneesh@in.ibm.com

define bttnobp
set $tasks_off=((size_t)&((struct task_struct *)0)->tasks)
set $pid_off=((size_t)&((struct task_struct *)0)->thread_group.next)
set $init_t=&init_task
set $next_t=(((char *)($init_t->tasks).next) - $tasks_off)
set var $stacksize = sizeof(union thread_union)
while ($next_t != $init_t)
set $next_t=(struct task_struct *)$next_t
printf “\npid %d; comm %s:\n”, $next_t.pid, $next_t.comm
printf “===================\n”
set var $stackp = $next_t.thread.sp
set var $stack_top = ($stackp & ~($stacksize - 1)) + $stacksize

    while ($stackp < $stack_top)
        if (*($stackp) > _stext && *($stackp) < _sinittext)
            info symbol *($stackp)
        end
        set $stackp += 4
    end
    set $next_th=(((char *)$next_t->thread_group.next) - $pid_off)
    while ($next_th != $next_t)
        set $next_th=(struct task_struct *)$next_th
        printf "\npid %d; comm %s:\n", $next_t.pid, $next_t.comm
        printf "===================\n"
        set var $stackp = $next_t.thread.sp
        set var $stack_top = ($stackp & ~($stacksize - 1)) + stacksize

        while ($stackp < $stack_top)
            if (*($stackp) > _stext && *($stackp) < _sinittext)
                info symbol *($stackp)
            end
            set $stackp += 4
        end
        set $next_th=(((char *)$next_th->thread_group.next) - $pid_off)
    end
    set $next_t=(char *)($next_t->tasks.next) - $tasks_off
end

end
document bttnobp
dump all thread stack traces on a kernel compiled with !CONFIG_FRAME_POINTER
end

define btthreadstack
set var $pid_task = $arg0

printf "\npid %d; comm %s:\n", $pid_task.pid, $pid_task.comm
printf "task struct: "
print $pid_task
printf "===================\n"
set var $stackp = $pid_task.thread.sp
set var $stacksize = sizeof(union thread_union)
set var $stack_top = ($stackp & ~($stacksize - 1)) + $stacksize
set var $stack_bot = ($stackp & ~($stacksize - 1))

set $stackp = *((unsigned long *) $stackp)
while (($stackp < $stack_top) && ($stackp > $stack_bot))
    set var $addr = *(((unsigned long *) $stackp) + 1)
    info symbol $addr
    set $stackp = *((unsigned long *) $stackp)
end

end
document btthreadstack
dump a thread stack using the given task structure pointer
end

define btt
set $tasks_off=((size_t)&((struct task_struct *)0)->tasks)
set $pid_off=((size_t)&((struct task_struct *)0)->thread_group.next)
set $init_t=&init_task
set $next_t=(((char *)($init_t->tasks).next) - $tasks_off)
while ($next_t != $init_t)
set $next_t=(struct task_struct *)$next_t
btthreadstack $next_t

    set $next_th=(((char *)$next_t->thread_group.next) - $pid_off)
    while ($next_th != $next_t)
        set $next_th=(struct task_struct *)$next_th
        btthreadstack $next_th
        set $next_th=(((char *)$next_th->thread_group.next) - $pid_off)
    end
    set $next_t=(char *)($next_t->tasks.next) - $tasks_off
end

end
document btt
dump all thread stack traces on a kernel compiled with CONFIG_FRAME_POINTER
end

define btpid
set var $pid = $arg0
set $tasks_off=((size_t)&((struct task_struct *)0)->tasks)
set $pid_off=((size_t)&((struct task_struct *)0)->thread_group.next)
set $init_t=&init_task
set $next_t=(((char *)($init_t->tasks).next) - $tasks_off)
set var $pid_task = 0

while ($next_t != $init_t)
    set $next_t=(struct task_struct *)$next_t

    if ($next_t.pid == $pid)
        set $pid_task = $next_t
    end

    set $next_th=(((char *)$next_t->thread_group.next) - $pid_off)
    while ($next_th != $next_t)
        set $next_th=(struct task_struct *)$next_th
        if ($next_th.pid == $pid)
            set $pid_task = $next_th
        end
        set $next_th=(((char *)$next_th->thread_group.next) - $pid_off)
    end
    set $next_t=(char *)($next_t->tasks.next) - $tasks_off
end

btthreadstack $pid_task

end
document btpid
backtrace of pid
end

define trapinfo
set var $pid = $arg0
set $tasks_off=((size_t)&((struct task_struct *)0)->tasks)
set $pid_off=((size_t)&((struct task_struct *)0)->thread_group.next)
set $init_t=&init_task
set $next_t=(((char *)($init_t->tasks).next) - $tasks_off)
set var $pid_task = 0

while ($next_t != $init_t)
    set $next_t=(struct task_struct *)$next_t

    if ($next_t.pid == $pid)
        set $pid_task = $next_t
    end

    set $next_th=(((char *)$next_t->thread_group.next) - $pid_off)
    while ($next_th != $next_t)
        set $next_th=(struct task_struct *)$next_th
        if ($next_th.pid == $pid)
            set $pid_task = $next_th
        end
        set $next_th=(((char *)$next_th->thread_group.next) - $pid_off)
    end
    set $next_t=(char *)($next_t->tasks.next) - $tasks_off
end

printf "Trapno %ld, cr2 0x%lx, error_code %ld\n", $pid_task.thread.trap_no, \
            $pid_task.thread.cr2, $pid_task.thread.error_code

end
document trapinfo
Run info threads and lookup pid of thread #1
‘trapinfo ‘ will tell you by which trap & possibly
address the kernel panicked.
end

define dump_log_idx
set $idx = $arg0
if ($argc > 1)
set $prev_flags = $arg1
else
set $prev_flags = 0
end
set $msg = ((struct printk_log ) (log_buf + $idx))
set $prefix = 1
set $newline = 1
set $log = log_buf + $idx + sizeof(
$msg)

# prev & LOG_CONT && !(msg->flags & LOG_PREIX)
if (($prev_flags & 8) && !($msg->flags & 4))
    set $prefix = 0
end

# msg->flags & LOG_CONT
if ($msg->flags & 8)
    # (prev & LOG_CONT && !(prev & LOG_NEWLINE))
    if (($prev_flags & 8) && !($prev_flags & 2))
        set $prefix = 0
    end
    # (!(msg->flags & LOG_NEWLINE))
    if (!($msg->flags & 2))
        set $newline = 0
    end
end

if ($prefix)
    printf "[%5lu.%06lu] ", $msg->ts_nsec / 1000000000, $msg->ts_nsec % 1000000000
end
if ($msg->text_len != 0)
    eval "printf \"%%%d.%ds\", $log", $msg->text_len, $msg->text_len
end
if ($newline)
    printf "\n"
end
if ($msg->dict_len > 0)
    set $dict = $log + $msg->text_len
    set $idx = 0
    set $line = 1
    while ($idx < $msg->dict_len)
        if ($line)
            printf " "
            set $line = 0
        end
        set $c = $dict[$idx]
        if ($c == '\0')
            printf "\n"
            set $line = 1
        else
            if ($c < ' ' || $c >= 127 || $c == '\\')
                printf "\\x%02x", $c
            else
                printf "%c", $c
            end
        end
        set $idx = $idx + 1
    end
    printf "\n"
end

end
document dump_log_idx
Dump a single log given its index in the log buffer. The first
parameter is the index into log_buf, the second is optional and
specified the previous log buffer’s flags, used for properly
formatting continued lines.
end

define dmesg
set $i = log_first_idx
set $end_idx = log_first_idx
set $prev_flags = 0

while (1)
    set $msg = ((struct printk_log *) (log_buf + $i))
    if ($msg->len == 0)
        set $i = 0
    else
        dump_log_idx $i $prev_flags
        set $i = $i + $msg->len
        set $prev_flags = $msg->flags
    end
    if ($i == $end_idx)
        loop_break
    end
end

end
document dmesg
print the kernel ring buffer
end