Subversion Repositories HelenOS

Rev

Rev 3124 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 3124 Rev 3126
1
/*
1
/*
2
 * Copyright (c) 2008 Jiri Svoboda
2
 * Copyright (c) 2008 Jiri Svoboda
3
 * All rights reserved.
3
 * All rights reserved.
4
 *
4
 *
5
 * Redistribution and use in source and binary forms, with or without
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions
6
 * modification, are permitted provided that the following conditions
7
 * are met:
7
 * are met:
8
 *
8
 *
9
 * - Redistributions of source code must retain the above copyright
9
 * - Redistributions of source code must retain the above copyright
10
 *   notice, this list of conditions and the following disclaimer.
10
 *   notice, this list of conditions and the following disclaimer.
11
 * - Redistributions in binary form must reproduce the above copyright
11
 * - Redistributions in binary form must reproduce the above copyright
12
 *   notice, this list of conditions and the following disclaimer in the
12
 *   notice, this list of conditions and the following disclaimer in the
13
 *   documentation and/or other materials provided with the distribution.
13
 *   documentation and/or other materials provided with the distribution.
14
 * - The name of the author may not be used to endorse or promote products
14
 * - The name of the author may not be used to endorse or promote products
15
 *   derived from this software without specific prior written permission.
15
 *   derived from this software without specific prior written permission.
16
 *
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
 */
27
 */
28
 
28
 
29
/** @addtogroup debug
29
/** @addtogroup debug
30
 * @{
30
 * @{
31
 */
31
 */
32
/** @file
32
/** @file
33
 */
33
 */
34
 
34
 
35
#include <stdio.h>
35
#include <stdio.h>
36
#include <stdlib.h>
36
#include <stdlib.h>
37
#include <assert.h>
37
#include <assert.h>
38
#include <sys/types.h>
38
#include <sys/types.h>
39
#include <errno.h>
39
#include <errno.h>
40
#include <udebug.h>
40
#include <udebug.h>
41
 
41
 
42
#include "../../../cons.h"
42
#include "../../../cons.h"
43
#include "../../../main.h"
43
#include "../../../main.h"
44
#include "../../../breakpoint.h"
44
#include "../../../breakpoint.h"
45
#include "../../../include/arch.h"
45
#include "../../../include/arch.h"
46
#include "../../../include/arch/arch.h"
46
#include "../../../include/arch/arch.h"
47
#include "../../../genarch/idec/idec.h"
47
#include "../../../genarch/idec/idec.h"
48
 
48
 
49
static istate_t istate;
49
static istate_t istate;
50
 
50
 
51
typedef enum {
51
typedef enum {
52
    /* Branch */
52
    /* Branch */
53
    OP_B,
53
    OP_B,
54
    OP_BL,
54
    OP_BL,
55
    OP_BLX1,
55
    OP_BLX1,
56
    OP_BLX2,
56
    OP_BLX2,
57
    OP_BX
57
    OP_BX,
-
 
58
 
-
 
59
    OP_MOV_PC_LR
58
} op_t;
60
} op_t;
59
 
61
 
60
typedef struct {
62
typedef struct {
61
    uint32_t mask;
63
    uint32_t mask;
62
    uint32_t value;
64
    uint32_t value;
63
    op_t op;
65
    op_t op;
64
} instr_desc_t;
66
} instr_desc_t;
65
 
67
 
66
static instr_desc_t decoding_table[] = {
68
static instr_desc_t decoding_table[] = {
67
    /* Unconditional branch (link) and exchange */
69
    /* Unconditional branch (link) and exchange */
68
    { 0xfe000000, 0xfa000000, OP_BLX1 },
70
    { 0xfe000000, 0xfa000000, OP_BLX1 },
69
    { 0x0ffffff0, 0x012fff30, OP_BLX2 },
71
    { 0x0ffffff0, 0x012fff30, OP_BLX2 },
70
    { 0x0ffffff0, 0x012fff10, OP_BX },
72
    { 0x0ffffff0, 0x012fff10, OP_BX },
71
 
73
 
72
    /*
74
    /*
73
     * Order is significant here, as the condition code for B, BL
75
     * Order is significant here, as the condition code for B, BL
74
     * (the top 4 bits) must not be 0xf, which is caught by BLX, BX
76
     * (the top 4 bits) must not be 0xf, which is caught by BLX, BX
75
     */
77
     */
76
 
78
 
77
    /* Branch (and link) */
79
    /* Branch (and link) */
78
    { 0x0f000000, 0x0a000000, OP_B },
80
    { 0x0f000000, 0x0a000000, OP_B },
79
    { 0x0f000000, 0x0b000000, OP_BL },
81
    { 0x0f000000, 0x0b000000, OP_BL },
80
 
82
 
-
 
83
    /* mov pc, lr */
-
 
84
    { 0xffffffff, 0xe1a0f00e, OP_MOV_PC_LR },
-
 
85
 
81
    { 0, 0, -1 }
86
    { 0, 0, -1 }
82
};
87
};
83
 
88
 
84
/** Sign-extend a value to 32 bits.
89
/** Sign-extend a value to 32 bits.
85
 *
90
 *
86
 * @param val   A signed value (of limited width)
91
 * @param val   A signed value (of limited width)
87
 * @param bits  Bit-width of value.
92
 * @param bits  Bit-width of value.
88
 * @return The value extended to a 32-bit signed integer.
93
 * @return The value extended to a 32-bit signed integer.
89
 */
94
 */
90
#define EXTS(val, bits) ((int32_t)(val) << (32 - (bits)) >> (32 - (bits)))
95
#define EXTS(val, bits) ((int32_t)(val) << (32 - (bits)) >> (32 - (bits)))
91
 
96
 
92
void arch_dthread_initialize(dthread_t *dt)
97
void arch_dthread_initialize(dthread_t *dt)
93
{
98
{
94
    dt->arch.singlestep = false;
99
    dt->arch.singlestep = false;
95
 
100
 
96
    bstore_initialize(&dt->arch.cur);
101
    bstore_initialize(&dt->arch.cur);
97
    bstore_initialize(&dt->arch.next[0]);
102
    bstore_initialize(&dt->arch.next[0]);
98
    bstore_initialize(&dt->arch.next[1]);
103
    bstore_initialize(&dt->arch.next[1]);
99
}
104
}
100
 
105
 
101
int arch_breakpoint_set(breakpoint_t *b)
106
int arch_breakpoint_set(breakpoint_t *b)
102
{
107
{
103
    int rc;
108
    int rc;
104
 
109
 
105
    rc = idec_breakpoint_set(b);
110
    rc = idec_breakpoint_set(b);
106
    if (rc != 0) return rc;
111
    if (rc != 0) return rc;
107
 
112
 
108
    return 0;
113
    return 0;
109
}
114
}
110
 
115
 
111
int arch_breakpoint_remove(breakpoint_t *b)
116
int arch_breakpoint_remove(breakpoint_t *b)
112
{
117
{
113
    return idec_breakpoint_remove(b);
118
    return idec_breakpoint_remove(b);
114
}
119
}
115
 
120
 
116
static int islot_read(uintptr_t addr, uint32_t *instr)
121
static int islot_read(uintptr_t addr, uint32_t *instr)
117
{
122
{
118
    int rc;
123
    int rc;
119
 
124
 
120
    rc = udebug_mem_read(app_phone, instr, addr, sizeof(uint32_t));
125
    rc = udebug_mem_read(app_phone, instr, addr, sizeof(uint32_t));
121
    if (rc != EOK) {
126
    if (rc != EOK) {
122
        cons_printf("Error reading memory address 0x%zx\n", addr);
127
        cons_printf("Error reading memory address 0x%zx\n", addr);
123
    }
128
    }
124
 
129
 
125
    return rc;
130
    return rc;
126
}
131
}
127
 
132
 
128
static int get_reg(dthread_t *dt, int reg_no, uint32_t *value)
133
static int get_reg(dthread_t *dt, int reg_no, uint32_t *value)
129
{
134
{
130
    int rc;
135
    int rc;
131
 
136
 
132
    cons_printf("get_reg...\n");
137
    cons_printf("get_reg...\n");
133
 
138
 
134
    if (reg_no == 0) {
139
    if (reg_no == 0) {
135
        *value = 0;
140
        *value = 0;
136
        return 0;
141
        return 0;
137
    }
142
    }
138
 
143
 
139
    rc = udebug_regs_read(app_phone, dt->hash, &istate);
144
    rc = udebug_regs_read(app_phone, dt->hash, &istate);
140
    if (rc < 0) return rc;
145
    if (rc < 0) return rc;
141
 
146
 
142
    switch (reg_no) {
147
    switch (reg_no) {
143
 
148
 
144
    case 0: *value = istate.r0; break;
149
    case 0: *value = istate.r0; break;
145
    case 1: *value = istate.r1; break;
150
    case 1: *value = istate.r1; break;
146
    case 2: *value = istate.r2; break;
151
    case 2: *value = istate.r2; break;
147
    case 3: *value = istate.r3; break;
152
    case 3: *value = istate.r3; break;
148
    case 4: *value = istate.r4; break;
153
    case 4: *value = istate.r4; break;
149
    case 5: *value = istate.r5; break;
154
    case 5: *value = istate.r5; break;
150
    case 6: *value = istate.r6; break;
155
    case 6: *value = istate.r6; break;
151
    case 7: *value = istate.r7; break;
156
    case 7: *value = istate.r7; break;
152
    case 8: *value = istate.r8; break;
157
    case 8: *value = istate.r8; break;
153
    case 9: *value = istate.r9; break;
158
    case 9: *value = istate.r9; break;
154
    case 10: *value = istate.r10; break;
159
    case 10: *value = istate.r10; break;
155
    case 11: *value = istate.r11; break;
160
    case 11: *value = istate.r11; break;
156
    case 12: *value = istate.r12; break;
161
    case 12: *value = istate.r12; break;
157
    case 13: *value = istate.sp; break;
162
    case 13: *value = istate.sp; break;
158
    case 14: *value = istate.lr; break;
163
    case 14: *value = istate.lr; break;
159
    case 15: *value = istate.pc; break;
164
    case 15: *value = istate.pc; break;
160
 
165
 
161
    }
166
    }
162
    printf("get_reg ok (0x%08x)\n", *value);
167
    printf("get_reg ok (0x%08x)\n", *value);
163
 
168
 
164
    return 0;
169
    return 0;
165
}
170
}
166
 
171
 
167
static op_t instr_decode(uint32_t instr)
172
static op_t instr_decode(uint32_t instr)
168
{
173
{
169
    instr_desc_t *idesc;
174
    instr_desc_t *idesc;
170
 
175
 
171
    idesc = &decoding_table[0];
176
    idesc = &decoding_table[0];
172
    while (idesc->op >= 0) {
177
    while (idesc->op >= 0) {
173
        if ((instr & idesc->mask) == idesc->value)
178
        if ((instr & idesc->mask) == idesc->value)
174
            return idesc->op;
179
            return idesc->op;
175
        ++idesc;
180
        ++idesc;
176
    }
181
    }
177
 
182
 
178
    return -1;
183
    return -1;
179
}
184
}
180
 
185
 
181
/** Get address of the instruction that will be executed after the current one.
186
/** Get address of the instruction that will be executed after the current one.
182
 *
187
 *
183
 * Assumptions: addr == PC, *addr is not covered by a BREAK.
188
 * Assumptions: addr == PC, *addr is not covered by a BREAK.
184
 *
189
 *
185
 * @param dt        Dthread on which to operate.
190
 * @param dt        Dthread on which to operate.
186
 * @param addr      Address of an instruction.
191
 * @param addr      Address of an instruction.
187
 * @param buffer    Buffer for storing up to 2 addresses.
192
 * @param buffer    Buffer for storing up to 2 addresses.
188
 * @return      Number of stored addresses or negative error code.
193
 * @return      Number of stored addresses or negative error code.
189
 */
194
 */
190
int get_next_addr(dthread_t *dt, uintptr_t addr, uintptr_t *buffer)
195
int get_next_addr(dthread_t *dt, uintptr_t addr, uintptr_t *buffer)
191
{
196
{
192
    uint32_t instr;
197
    uint32_t instr;
193
    int32_t imm, h;
198
    int32_t imm, h;
194
    uint32_t regv;
199
    uint32_t regv;
195
    op_t op;
200
    op_t op;
196
    int rc;
201
    int rc;
197
    int n;
202
    int n;
198
 
203
 
199
    rc = islot_read(addr, &instr);
204
    rc = islot_read(addr, &instr);
200
    if (rc != 0) return rc;
205
    if (rc != 0) return rc;
201
 
206
 
202
    op = instr_decode(instr);
207
    op = instr_decode(instr);
203
 
208
 
204
    switch (op) {
209
    switch (op) {
205
    /* Branch (and link) */
210
    /* Branch (and link) */
206
    case OP_B:
211
    case OP_B:
207
    case OP_BL:
212
    case OP_BL:
208
        /* imm is a 24-bit signed integer */
213
        /* imm is a 24-bit signed integer */
209
        imm = EXTS(instr & 0x00ffffff, 24);
214
        imm = EXTS(instr & 0x00ffffff, 24);
210
        buffer[0] = (addr + 8) + (imm << 2);
215
        buffer[0] = (addr + 8) + (imm << 2);
211
        buffer[1] = addr + 4;
216
        buffer[1] = addr + 4;
212
        n = 2;
217
        n = 2;
213
        break;
218
        break;
214
 
219
 
215
    /* Unconditional branch, link and exchange */
220
    /* Unconditional branch, link and exchange */
216
    case OP_BLX1:
221
    case OP_BLX1:
217
        /* imm is a 24-bit signed integer */
222
        /* imm is a 24-bit signed integer */
218
        imm = EXTS(instr & 0x00ffffff, 24);
223
        imm = EXTS(instr & 0x00ffffff, 24);
219
        h = (instr & 0x01000000) ? 1 : 0;
224
        h = (instr & 0x01000000) ? 1 : 0;
220
        buffer[0] = (addr + 8) + (imm << 2) + (h << 1);
225
        buffer[0] = (addr + 8) + (imm << 2) + (h << 1);
221
        n = 1;
226
        n = 1;
222
        break;
227
        break;
223
 
228
 
224
    case OP_BLX2:
229
    case OP_BLX2:
225
    case OP_BX:
230
    case OP_BX:
226
        /* BLX (2), BX */
231
        /* BLX (2), BX */
227
        rc = get_reg(dt, instr & 0xf, &regv);
232
        rc = get_reg(dt, instr & 0xf, &regv);
228
        if (rc != 0) return rc;
233
        if (rc != 0) return rc;
229
 
234
 
230
        buffer[0] = regv & ~0x1;
235
        buffer[0] = regv & ~0x1;
231
        buffer[1] = addr + 4;
236
        buffer[1] = addr + 4;
232
        n = 2;
237
        n = 2;
233
        break;
238
        break;
234
 
239
 
-
 
240
    case OP_MOV_PC_LR:
-
 
241
        /* mov pc, lr - this is typically used as 'return' */
-
 
242
        rc = get_reg(dt, 14 /* lr */, &regv);
-
 
243
        if (rc != 0) return rc;
-
 
244
 
-
 
245
        buffer[0] = regv & ~0x1;
-
 
246
        printf("mov pc, lr ---> 0x%x\n", buffer[0]);
-
 
247
        n = 1;
-
 
248
        break;
-
 
249
 
235
    /* TODO: handle instructions writing r15 */
250
    /* TODO: handle general case of instructions writing r15(pc) */
236
 
251
 
237
    default:
252
    default:
238
        /* Regular instruction */  
253
        /* Regular instruction */  
239
        buffer[0] = addr + 4;
254
        buffer[0] = addr + 4;
240
        n = 1;
255
        n = 1;
241
        break;
256
        break;
242
    }
257
    }
243
 
258
 
244
    return n;
259
    return n;
245
}
260
}
246
 
261
 
247
void arch_event_breakpoint(thash_t thread_hash)
262
void arch_event_breakpoint(thash_t thread_hash)
248
{
263
{
249
    idec_event_breakpoint(thread_hash);
264
    idec_event_breakpoint(thread_hash);
250
}
265
}
251
 
266
 
252
void arch_event_trap(dthread_t *dt)
267
void arch_event_trap(dthread_t *dt)
253
{
268
{
254
    /* Unused */
269
    /* Unused */
255
    (void)dt;
270
    (void)dt;
256
}
271
}
257
 
272
 
258
void arch_dump_regs(thash_t thash)
273
void arch_dump_regs(thash_t thash)
259
{
274
{
260
    /* TODO */
275
    /* TODO */
261
}
276
}
262
 
277
 
263
void arch_singlestep(dthread_t *dt)
278
void arch_singlestep(dthread_t *dt)
264
{
279
{
265
    idec_singlestep(dt);
280
    idec_singlestep(dt);
266
}
281
}
267
 
282
 
268
/** @}
283
/** @}
269
 */
284
 */
270
 
285