ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/sigsegv.cpp
(Generate patch)

Comparing BasiliskII/src/Unix/sigsegv.cpp (file contents):
Revision 1.41 by cebix, 2004-01-12T15:29:25Z vs.
Revision 1.44 by gbeauche, 2004-01-21T23:14:28Z

# Line 281 | Line 281 | static void powerpc_decode_instruction(i
281   #undef  SIGSEGV_FAULT_ADDRESS
282   #define SIGSEGV_FAULT_ADDRESS                   sip->si_ptr
283   #endif
284 + #if (defined(arm) || defined(__arm__))
285 + #include <asm/ucontext.h> /* use kernel structure, glibc may not be in sync */
286 + #define SIGSEGV_CONTEXT_REGS                    (((struct ucontext *)scp)->uc_mcontext)
287 + #define SIGSEGV_FAULT_INSTRUCTION               (SIGSEGV_CONTEXT_REGS.arm_pc)
288 + #define SIGSEGV_REGISTER_FILE                   (&SIGSEGV_CONTEXT_REGS.arm_r0)
289 + #define SIGSEGV_SKIP_INSTRUCTION                arm_skip_instruction
290 + #endif
291   #endif
292   #endif
293  
# Line 320 | Line 327 | static void powerpc_decode_instruction(i
327   #define SIGSEGV_FAULT_ADDRESS                   get_fault_address(scp)
328   #define SIGSEGV_FAULT_INSTRUCTION               scp->sc_pc
329   #endif
330 + #if (defined(arm) || defined(__arm__))
331 + #define SIGSEGV_FAULT_HANDLER_ARGLIST   int sig, int r1, int r2, int r3, struct sigcontext sc
332 + #define SIGSEGV_FAULT_HANDLER_ARGLIST_1 struct sigcontext *scp
333 + #define SIGSEGV_FAULT_HANDLER_ARGS              &sc
334 + #define SIGSEGV_FAULT_ADDRESS                   scp->fault_address
335 + #define SIGSEGV_FAULT_INSTRUCTION               scp->arm_pc
336 + #define SIGSEGV_REGISTER_FILE                   &scp->arm_r0
337 + #define SIGSEGV_SKIP_INSTRUCTION                arm_skip_instruction
338 + #endif
339   #endif
340  
341   // Irix 5 or 6 on MIPS
# Line 1240 | Line 1256 | static bool sparc_skip_instruction(unsig
1256   #endif
1257   #endif
1258  
1259 + // Decode and skip ARM instruction
1260 + #if (defined(arm) || defined(__arm__))
1261 + enum {
1262 + #if (defined(__linux__))
1263 +  ARM_REG_PC = 15,
1264 +  ARM_REG_CPSR = 16
1265 + #endif
1266 + };
1267 + static bool arm_skip_instruction(unsigned long * regs)
1268 + {
1269 +  unsigned int * pc = (unsigned int *)regs[ARM_REG_PC];
1270 +
1271 +  if (pc == 0)
1272 +        return false;
1273 +
1274 + #if DEBUG
1275 +  printf("IP: %p [%08x]\n", pc, pc[0]);
1276 + #endif
1277 +
1278 +  transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
1279 +  transfer_size_t transfer_size = SIZE_UNKNOWN;
1280 +  enum { op_sdt = 1, op_sdth = 2 };
1281 +  int op = 0;
1282 +
1283 +  // Handle load/store instructions only
1284 +  const unsigned int opcode = pc[0];
1285 +  switch ((opcode >> 25) & 7) {
1286 +  case 0: // Halfword and Signed Data Transfer (LDRH, STRH, LDRSB, LDRSH)
1287 +        op = op_sdth;
1288 +        // Determine transfer size (S/H bits)
1289 +        switch ((opcode >> 5) & 3) {
1290 +        case 0: // SWP instruction
1291 +          break;
1292 +        case 1: // Unsigned halfwords
1293 +        case 3: // Signed halfwords
1294 +          transfer_size = SIZE_WORD;
1295 +          break;
1296 +        case 2: // Signed byte
1297 +          transfer_size = SIZE_BYTE;
1298 +          break;
1299 +        }
1300 +        break;
1301 +  case 2:
1302 +  case 3: // Single Data Transfer (LDR, STR)
1303 +        op = op_sdt;
1304 +        // Determine transfer size (B bit)
1305 +        if (((opcode >> 22) & 1) == 1)
1306 +          transfer_size = SIZE_BYTE;
1307 +        else
1308 +          transfer_size = SIZE_LONG;
1309 +        break;
1310 +  default:
1311 +        // FIXME: support load/store mutliple?
1312 +        return false;
1313 +  }
1314 +
1315 +  // Check for invalid transfer size (SWP instruction?)
1316 +  if (transfer_size == SIZE_UNKNOWN)
1317 +        return false;
1318 +
1319 +  // Determine transfer type (L bit)
1320 +  if (((opcode >> 20) & 1) == 1)
1321 +        transfer_type = SIGSEGV_TRANSFER_LOAD;
1322 +  else
1323 +        transfer_type = SIGSEGV_TRANSFER_STORE;
1324 +
1325 +  // Compute offset
1326 +  int offset;
1327 +  if (((opcode >> 25) & 1) == 0) {
1328 +        if (op == op_sdt)
1329 +          offset = opcode & 0xfff;
1330 +        else if (op == op_sdth) {
1331 +          int rm = opcode & 0xf;
1332 +          if (((opcode >> 22) & 1) == 0) {
1333 +                // register offset
1334 +                offset = regs[rm];
1335 +          }
1336 +          else {
1337 +                // immediate offset
1338 +                offset = ((opcode >> 4) & 0xf0) | (opcode & 0x0f);
1339 +          }
1340 +        }
1341 +  }
1342 +  else {
1343 +        const int rm = opcode & 0xf;
1344 +        const int sh = (opcode >> 7) & 0x1f;
1345 +        if (((opcode >> 4) & 1) == 1) {
1346 +          // we expect only legal load/store instructions
1347 +          printf("FATAL: invalid shift operand\n");
1348 +          return false;
1349 +        }
1350 +        const unsigned int v = regs[rm];
1351 +        switch ((opcode >> 5) & 3) {
1352 +        case 0: // logical shift left
1353 +          offset = sh ? v << sh : v;
1354 +          break;
1355 +        case 1: // logical shift right
1356 +          offset = sh ? v >> sh : 0;
1357 +          break;
1358 +        case 2: // arithmetic shift right
1359 +          if (sh)
1360 +                offset = ((signed int)v) >> sh;
1361 +          else
1362 +                offset = (v & 0x80000000) ? 0xffffffff : 0;
1363 +          break;
1364 +        case 3: // rotate right
1365 +          if (sh)
1366 +                offset = (v >> sh) | (v << (32 - sh));
1367 +          else
1368 +                offset = (v >> 1) | ((regs[ARM_REG_CPSR] << 2) & 0x80000000);
1369 +          break;
1370 +        }
1371 +  }
1372 +  if (((opcode >> 23) & 1) == 0)
1373 +        offset = -offset;
1374 +
1375 +  int rd = (opcode >> 12) & 0xf;
1376 +  int rn = (opcode >> 16) & 0xf;
1377 + #if DEBUG
1378 +  static const char * reg_names[] = {
1379 +        "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
1380 +        "r9", "r9", "sl", "fp", "ip", "sp", "lr", "pc"
1381 +  };
1382 +  printf("%s %s register %s\n",
1383 +                 transfer_size == SIZE_BYTE ? "byte" :
1384 +                 transfer_size == SIZE_WORD ? "word" :
1385 +                 transfer_size == SIZE_LONG ? "long" : "unknown",
1386 +                 transfer_type == SIGSEGV_TRANSFER_LOAD ? "load to" : "store from",
1387 +                 reg_names[rd]);
1388 + #endif
1389 +
1390 +  unsigned int base = regs[rn];
1391 +  if (((opcode >> 24) & 1) == 1)
1392 +        base += offset;
1393 +
1394 +  if (transfer_type == SIGSEGV_TRANSFER_LOAD)
1395 +        regs[rd] = 0;
1396 +
1397 +  if (((opcode >> 24) & 1) == 0)                // post-index addressing
1398 +        regs[rn] += offset;
1399 +  else if (((opcode >> 21) & 1) == 1)   // write-back address into base
1400 +        regs[rn] = base;
1401 +
1402 +  regs[ARM_REG_PC] += 4;
1403 +  return true;
1404 + }
1405 + #endif
1406 +
1407 +
1408   // Fallbacks
1409   #ifndef SIGSEGV_FAULT_INSTRUCTION
1410   #define SIGSEGV_FAULT_INSTRUCTION               SIGSEGV_INVALID_PC
# Line 1295 | Line 1460 | static bool handle_badaccess(SIGSEGV_FAU
1460                  }
1461                  break;
1462   #endif
1463 +        case SIGSEGV_RETURN_FAILURE:
1464 +                return false;
1465          }
1466          
1467          // We can't do anything with the fault_address, dump state?
# Line 1697 | Line 1864 | static sigsegv_return_t sigsegv_test_han
1864   #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
1865   static sigsegv_return_t sigsegv_insn_handler(sigsegv_address_t fault_address, sigsegv_address_t instruction_address)
1866   {
1867 + #if DEBUG
1868 +        printf("sigsegv_insn_handler(%p, %p)\n", fault_address, instruction_address);
1869 + #endif
1870          if (((unsigned long)fault_address - (unsigned long)page) < page_size) {
1871   #ifdef __GNUC__
1872                  // Make sure reported fault instruction address falls into
# Line 1831 | Line 2001 | int main(void)
2001          TEST_SKIP_INSTRUCTION(unsigned short);
2002          TEST_SKIP_INSTRUCTION(unsigned int);
2003          TEST_SKIP_INSTRUCTION(unsigned long);
2004 +        TEST_SKIP_INSTRUCTION(signed char);
2005 +        TEST_SKIP_INSTRUCTION(signed short);
2006 +        TEST_SKIP_INSTRUCTION(signed int);
2007 +        TEST_SKIP_INSTRUCTION(signed long);
2008   L_e_region2:
2009  
2010          if (!arch_insn_skipper_tests())

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines