Subversion Repositories HelenOS

Rev

Go to most recent revision | Details | 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,
57
    OP_BX
58
} op_t;
59
 
60
typedef struct {
61
    uint32_t mask;
62
    uint32_t value;
63
    op_t op;
64
} instr_desc_t;
65
 
66
static instr_desc_t decoding_table[] = {
67
    /* Unconditional branch (link) and exchange */
68
    { 0xfe000000, 0xfa000000, OP_BLX1 },
69
    { 0x0ffffff0, 0x012fff30, OP_BLX2 },
70
    { 0x0ffffff0, 0x012fff10, OP_BX },
71
 
72
    /*
73
     * 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
75
     */
76
 
77
    /* Branch (and link) */
78
    { 0x0f000000, 0x0a000000, OP_B },
79
    { 0x0f000000, 0x0b000000, OP_BL },
80
 
81
    { 0, 0, -1 }
82
};
83
 
84
/** Sign-extend a value to 32 bits.
85
 *
86
 * @param val   A signed value (of limited width)
87
 * @param bits  Bit-width of value.
88
 * @return The value extended to a 32-bit signed integer.
89
 */
90
#define EXTS(val, bits) ((int32_t)(val) << (32 - (bits)) >> (32 - (bits)))
91
 
92
void arch_dthread_initialize(dthread_t *dt)
93
{
94
    dt->arch.singlestep = false;
95
 
96
    bstore_initialize(&dt->arch.cur);
97
    bstore_initialize(&dt->arch.next[0]);
98
    bstore_initialize(&dt->arch.next[1]);
99
}
100
 
101
int arch_breakpoint_set(breakpoint_t *b)
102
{
103
    int rc;
104
 
105
    rc = idec_breakpoint_set(b);
106
    if (rc != 0) return rc;
107
 
108
    return 0;
109
}
110
 
111
int arch_breakpoint_remove(breakpoint_t *b)
112
{
113
    return idec_breakpoint_remove(b);
114
}
115
 
116
static int islot_read(uintptr_t addr, uint32_t *instr)
117
{
118
    int rc;
119
 
120
    rc = udebug_mem_read(app_phone, instr, addr, sizeof(uint32_t));
121
    if (rc != EOK) {
122
        cons_printf("Error reading memory address 0x%zx\n", addr);
123
    }
124
 
125
    return rc;
126
}
127
 
128
static int get_reg(dthread_t *dt, int reg_no, uint32_t *value)
129
{
130
    int rc;
131
 
132
    cons_printf("get_reg...\n");
133
 
134
    if (reg_no == 0) {
135
        *value = 0;
136
        return 0;
137
    }
138
 
139
    rc = udebug_regs_read(app_phone, dt->hash, &istate);
140
    if (rc < 0) return rc;
141
 
142
    switch (reg_no) {
143
 
144
    case 0: *value = istate.r0; break;
145
    case 1: *value = istate.r1; break;
146
    case 2: *value = istate.r2; break;
147
    case 3: *value = istate.r3; break;
148
    case 4: *value = istate.r4; break;
149
    case 5: *value = istate.r5; break;
150
    case 6: *value = istate.r6; break;
151
    case 7: *value = istate.r7; break;
152
    case 8: *value = istate.r8; break;
153
    case 9: *value = istate.r9; break;
154
    case 10: *value = istate.r10; break;
155
    case 11: *value = istate.r11; break;
156
    case 12: *value = istate.r12; break;
157
    case 13: *value = istate.sp; break;
158
    case 14: *value = istate.lr; break;
159
    case 15: *value = istate.pc; break;
160
 
161
    }
162
    printf("get_reg ok (0x%08x)\n", *value);
163
 
164
    return 0;
165
}
166
 
167
static op_t instr_decode(uint32_t instr)
168
{
169
    instr_desc_t *idesc;
170
 
171
    idesc = &decoding_table[0];
172
    while (idesc->op >= 0) {
173
        if ((instr & idesc->mask) == idesc->value)
174
            return idesc->op;
175
        ++idesc;
176
    }
177
 
178
    return -1;
179
}
180
 
181
/** Get address of the instruction that will be executed after the current one.
182
 *
183
 * Assumptions: addr == PC, *addr is not covered by a BREAK.
184
 *
185
 * @param dt        Dthread on which to operate.
186
 * @param addr      Address of an instruction.
187
 * @param buffer    Buffer for storing up to 2 addresses.
188
 * @return      Number of stored addresses or negative error code.
189
 */
190
int get_next_addr(dthread_t *dt, uintptr_t addr, uintptr_t *buffer)
191
{
192
    uint32_t instr;
193
    int32_t imm, h;
194
    uint32_t regv;
195
    op_t op;
196
    int rc;
197
    int n;
198
 
199
    rc = islot_read(addr, &instr);
200
    if (rc != 0) return rc;
201
 
202
    op = instr_decode(instr);
203
 
204
    switch (op) {
205
    /* Branch (and link) */
206
    case OP_B:
207
    case OP_BL:
208
        /* imm is a 24-bit signed integer */
209
        imm = EXTS(instr & 0x00ffffff, 24);
210
        buffer[0] = (addr + 8) + (imm << 2);
211
        buffer[1] = addr + 4;
212
        n = 2;
213
        break;
214
 
215
    /* Unconditional branch, link and exchange */
216
    case OP_BLX1:
217
        /* imm is a 24-bit signed integer */
218
        imm = EXTS(instr & 0x00ffffff, 24);
219
        h = (instr & 0x01000000) ? 1 : 0;
220
        buffer[0] = (addr + 8) + (imm << 2) + (h << 1);
221
        n = 1;
222
        break;
223
 
224
    case OP_BLX2:
225
    case OP_BX:
226
        /* BLX (2), BX */
227
        rc = get_reg(dt, instr & 0xf, &regv);
228
        if (rc != 0) return rc;
229
 
230
        buffer[0] = regv & ~0x1;
231
        buffer[1] = addr + 4;
232
        n = 2;
233
        break;
234
 
235
    /* TODO: handle instructions writing r15 */
236
 
237
    default:
238
        /* Regular instruction */  
239
        buffer[0] = addr + 4;
240
        n = 1;
241
        break;
242
    }
243
 
244
    return n;
245
}
246
 
247
void arch_event_breakpoint(thash_t thread_hash)
248
{
249
    idec_event_breakpoint(thread_hash);
250
}
251
 
252
void arch_event_trap(dthread_t *dt)
253
{
254
    /* Unused */
255
    (void)dt;
256
}
257
 
258
void arch_dump_regs(thash_t thash)
259
{
260
    /* TODO */
261
}
262
 
263
void arch_singlestep(dthread_t *dt)
264
{
265
    idec_singlestep(dt);
266
}
267
 
268
/** @}
269
 */