This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
Re: [RFC 3/7] Add basic Linux kernel support
- From: Yao Qi <qiyaoltc at gmail dot com>
- To: Yao Qi <qiyaoltc at gmail dot com>
- Cc: Philipp Rudo <prudo at linux dot vnet dot ibm dot com>, gdb-patches at sourceware dot org, peter dot griffin at linaro dot org, yao dot qi at arm dot com, arnez at linux dot vnet dot ibm dot com
- Date: Thu, 09 Feb 2017 13:05:58 +0000
- Subject: Re: [RFC 3/7] Add basic Linux kernel support
- Authentication-results: sourceware.org; auth=none
- References: <20170112113217.48852-1-prudo@linux.vnet.ibm.com> <20170112113217.48852-4-prudo@linux.vnet.ibm.com> <20170207105403.GA1630@E107787-LIN>
Yao Qi <qiyaoltc@gmail.com> writes:
> I am playing your first three patches on x86_64 with some hacks.
> I write a small program with the same linux kernel "signature", and
> want GDB treat it as a linux kernel.
>
I make some progress on writing such small test case,
see the code below. I hacked lk_try_push_target not to do the
sanity check, and not to call lk_try_push_target in
lk_observer_inferior_created, so that I can push this target layer when
I want.
(gdb) break stop^M
Breakpoint 2 at 0x400711: file /home/yao/SourceCode/gnu/gdb/git/gdb/testsuite/gdb.base/linux-kernel.c, line 104.^M
(gdb) continue^M
Continuing.^M
^M
Breakpoint 2, stop () at /home/yao/SourceCode/gnu/gdb/git/gdb/testsuite/gdb.base/linux-kernel.c:104^M
104 {}^M
(gdb) PASS: gdb.base/linux-kernel.exp: continue to breakpoint: stop
at this point, the list of tasks are set up, switch to linux-kernel
target layer,
target linux-kernel^M
[New process 8001]^M
(gdb) PASS: gdb.base/linux-kernel.exp: target linux-kernel
maintenance print target-stack^M
The current target stack is:^M
- linux-kernel (linux kernel support)^M
- native (Native process)^M
- exec (Local exec file)^M
- None (None)^M
It works! In this way, we can test that GDB can successfully parse the
these data structures in Linux kernel without Linux kernel image at all.
Then, we can generate a coredump,
(gdb) generate-core-file
Saved corefile core.9614
Remove the hack in lk_observer_inferior_created, so that GDB can
automatically push linux-kernel target layer,
$ ./gdb ./testsuite/outputs/gdb.base/linux-kernel/linux-kernel ./core.9614
[New LWP 9614]
[New process 9614]
Core was generated by `/scratch/yao/gdb/build-git/x86_64/gdb/testsuite/outputs/gdb.base/linux-kernel/li'.
Program terminated with signal SIGTRAP, Trace/breakpoint trap.
#0 stop () at /home/yao/SourceCode/gnu/gdb/git/gdb/testsuite/gdb.base/linux-kernel.c:104
104 {}
[Current thread is 1 (PID: 9614*, 0x602010)]
(gdb) maintenance print target-stack
The current target stack is:
- linux-kernel (linux kernel support)
- core (Local core dump file)
- exec (Local exec file)
- None (None)
The next step would be extending the test case to a multi-threaded
program, so that we can create task lists for these threads, and
generate coredump which is similar to the kernel coredump.
--
Yao (齐尧)
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
static char linux_banner[10];
static int _stext = 0;
static int _etext = 0;
typedef int pid_t;
struct list_head
{
struct list_head *next, *prev;
};
#define LIST_HEAD_INIT(name) (struct list_head) { &(name), &(name) }
struct thread_struct
{};
struct task_struct
{
struct list_head tasks;
pid_t pid;
pid_t tgid;
struct list_head thread_group;
char comm[20];
struct thread_struct thread;
};
struct rq
{
struct task_struct *curr;
};
#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
#define BITS_PER_BYTE 8
#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof (long))
#define DECLARE_BITMAP(name,bits) \
unsigned long name[BITS_TO_LONGS(bits)]
#define NR_CPUS 10
struct cpumask { DECLARE_BITMAP(bits, NR_CPUS); };
struct cpumask __cpu_online_mask;
static void
cpumask_set_cpu (unsigned int cpu, struct cpumask* dstp)
{
dstp->bits[cpu / (BITS_PER_BYTE * sizeof (long))]
|= 1UL << (cpu % (BITS_PER_BYTE * sizeof (long)));
}
struct task_struct init_task;;
struct rq runqueues[NR_CPUS];
struct cpumask baz;
unsigned long __per_cpu_offset[NR_CPUS];
struct mm_struct
{};
struct mm_struct init_mm;
static void
setup (void)
{
int i;
struct task_struct *task;
/* Set up __per_cpu_offset. */
for (i = 0; i < NR_CPUS; i++)
__per_cpu_offset[i] = i * sizeof (runqueues[0]);
/* Mark cpu 0 is online. */
cpumask_set_cpu (0, &__cpu_online_mask);
init_task.tasks = LIST_HEAD_INIT(init_task.tasks);
init_task.thread_group = LIST_HEAD_INIT(init_task.thread_group);
task = malloc (sizeof (struct task_struct));
memset (task, 0, sizeof (sizeof (struct task_struct)));
task->pid = getpid ();
runqueues[0].curr = task;
/* Chain it tasks list. */
init_task.tasks.next = (struct list_head *) task;
init_task.tasks.prev = (struct list_head *) task;
task->tasks.next = (struct list_head *) &init_task;
task->tasks.prev = (struct list_head *) &init_task;
/* TASK is the group leader. */
task->thread_group = LIST_HEAD_INIT(task->thread_group);
}
static void
stop (void)
{}
int
main (void)
{
setup ();
stop ();
return 0;
}