aboutsummaryrefslogtreecommitdiffstats
path: root/tools/debugger/pdb/linux-2.6-module/debug.c
blob: 744be03b732e278e51162d8145a1a5c9dd07ea8b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
/*
 * debug.c
 * pdb debug functionality for processes.
 */


#include <linux/module.h>
#include <linux/sched.h>
#include <asm-xen/asm-i386/ptrace.h>
#include <asm-xen/xen-public/xen.h>

#include "pdb_module.h"

EXPORT_SYMBOL(pdb_attach);
EXPORT_SYMBOL(pdb_detach);

int
pdb_attach (int pid)
{
    struct task_struct *target;
    u32 rc = 0;

    printk ("pdb attach: 0x%x\n", pid);

    read_lock(&tasklist_lock);
    target = find_task_by_pid(pid);
    if (target)
        get_task_struct(target);
    read_unlock(&tasklist_lock);

    force_sig(SIGSTOP, target);                    /* force_sig_specific ??? */

    return rc;
}

int
pdb_detach (int pid)
{
    int rc = 0;
    struct task_struct *target;

    printk ("pdb detach: 0x%x\n", pid);

    read_lock(&tasklist_lock);
    target = find_task_by_pid(pid);
    if (target)
        get_task_struct(target);
    read_unlock(&tasklist_lock);

    wake_up_process(target);

    return rc;
}

/*
 * from linux-2.6.11/arch/i386/kernel/ptrace.c::getreg()
 */
int
pdb_read_register (int pid, pdb_op_rd_reg_p op, unsigned long *dest)
{
    int rc = 0;
    struct task_struct *target;
    unsigned long offset;
    unsigned char *stack = 0L;

    *dest = ~0UL;

    read_lock(&tasklist_lock);
    target = find_task_by_pid(pid);
    if (target)
        get_task_struct(target);
    read_unlock(&tasklist_lock);

    switch (op->reg)
    {
    case FS:
        *dest = target->thread.fs;
        break;
    case GS:
        *dest = target->thread.gs;
        break;
    case DS:
    case ES:
    case SS:
    case CS:
        *dest = 0xffff;
        /* fall through */
    default:
        if (op->reg > GS)
            op->reg -= 2;

        offset = op->reg * sizeof(long);
        offset -= sizeof(struct pt_regs);
        stack = (unsigned char *)target->thread.esp0;
        stack += offset;
        *dest &= *((int *)stack);
    }

    /*
    printk ("pdb read register: 0x%x %2d 0x%p 0x%lx\n", 
            pid, op->reg, stack, *dest);
    */

    return rc;
}

/*
 * from linux-2.6.11/arch/i386/kernel/ptrace.c::putreg()
 */
int
pdb_write_register (int pid, pdb_op_wr_reg_p op)
{
    int rc = 0;
    struct task_struct *target;
    unsigned long offset;
    unsigned char *stack;
    unsigned long value = op->value;

    /*
    printk ("pdb write register: 0x%x %2d 0x%lx\n", pid, op->reg, value);
    */

    read_lock(&tasklist_lock);
    target = find_task_by_pid(pid);
    if (target)
        get_task_struct(target);
    read_unlock(&tasklist_lock);

    switch (op->reg)
    {
    case FS:
        target->thread.fs = value;
        return rc;
    case GS:
        target->thread.gs = value;
        return rc;
    case DS:
    case ES:
        value &= 0xffff;
        break;
    case SS:
    case CS:
        value &= 0xffff;
        break;
    case EFL:
        break;
    }

    if (op->reg > GS)
        op->reg -= 2;
    offset = op->reg * sizeof(long);
    offset -= sizeof(struct pt_regs);
    stack = (unsigned char *)target->thread.esp0;
    stack += offset;
    *(unsigned long *) stack = op->value;

    return rc;
}

/*
 * Local variables:
 * mode: C
 * c-set-style: "BSD"
 * c-basic-offset: 4
 * tab-width: 4
 * indent-tabs-mode: nil
 * End:
 */