Subversion Repositories HelenOS

Rev

Rev 3124 | Details | Compare with Previous | Last modification | View Log | RSS feed

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