summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOxore <oxore@protonmail.com>2023-04-27 23:28:25 +0300
committerOxore <oxore@protonmail.com>2023-04-27 23:28:25 +0300
commit9de14dc1635829fa162731d0ef179c3b2b7ae5be (patch)
treeaf2312b88952565588c2ce12e374461fa7148d29
parente57b4a0a762c7951de3d9c9cc1c5eff886296835 (diff)
Fix bugs found on random tests
-rw-r--r--common.h8
-rw-r--r--disasm.cpp122
-rw-r--r--test_random.bash14
3 files changed, 97 insertions, 47 deletions
diff --git a/common.h b/common.h
index 34ba934..1a99f75 100644
--- a/common.h
+++ b/common.h
@@ -13,19 +13,19 @@ constexpr size_t kInstructionSizeStepBytes = 2;
constexpr size_t kRomSizeBytes = 4 * 1024 * 1024;
constexpr size_t kDisasmMapSizeElements = kRomSizeBytes / kInstructionSizeStepBytes;
-static inline size_t Min(size_t a, size_t b) { return a < b ? a : b; }
+constexpr size_t Min(size_t a, size_t b) { return a < b ? a : b; }
-static inline uint16_t GetU16BE(uint8_t *buffer)
+constexpr uint16_t GetU16BE(uint8_t *buffer)
{
return (static_cast<uint16_t>(buffer[0]) << 8) | static_cast<uint16_t>(buffer[1]);
}
-static inline int16_t GetI16BE(uint8_t *buffer)
+constexpr int16_t GetI16BE(uint8_t *buffer)
{
return (static_cast<uint16_t>(buffer[0]) << 8) | static_cast<uint16_t>(buffer[1]);
}
-static inline int32_t GetI32BE(uint8_t *buffer)
+constexpr int32_t GetI32BE(uint8_t *buffer)
{
return (static_cast<uint32_t>(buffer[0]) << 24) |
(static_cast<uint32_t>(buffer[1]) << 16) |
diff --git a/disasm.cpp b/disasm.cpp
index 3b996a4..326300f 100644
--- a/disasm.cpp
+++ b/disasm.cpp
@@ -42,7 +42,7 @@ static void disasm_jsr_jmp(
case 4: // 4ea0..4ea7 / 4ee0..4ee7
break;
case 5: // 4ea8..4eaf / 4ee8..4eef, Displacement
- {
+ if (node.offset + kInstructionSizeStepBytes < code.occupied_size) {
// NOTE: dynamic jump, branch_addr may possibly be obtained during
// the trace
node.size = kInstructionSizeStepBytes * 2;
@@ -51,12 +51,18 @@ static void disasm_jsr_jmp(
snprintf(node.arguments, kArgsBufferSize, "%%a%d@(%d:w)", xn, dispmt);
return;
}
+ break;
case 6: // 4eb0..4eb7 / 4ef0..4ef7, Brief Extension Word
- {
+ if (node.offset + kInstructionSizeStepBytes < code.occupied_size) {
// NOTE: dynamic jump, branch_addr may possibly be obtained during
// the trace
node.size = kInstructionSizeStepBytes * 2;
const uint16_t briefext = GetU16BE(code.buffer + node.offset + kInstructionSizeStepBytes);
+ if (briefext & 0x0700) {
+ // briefext must have zeros on 8, 9 an 10-th bits,
+ // i.e. xxxx_x000_xxxx_xxxx
+ break;
+ }
const char reg = ((briefext >> 15) & 1) ? 'a' : 'd';
const int xn2 = (briefext >> 12) & 7;
const char size_spec = ((briefext >> 11) & 1) ? 'l' : 'w';
@@ -66,10 +72,11 @@ static void disasm_jsr_jmp(
"%%a%d@(%d,%%%c%d:%c)", xn, dispmt, reg, xn2, size_spec);
return;
}
+ break;
case 7: // 4eb8..4ebf / 4ef8..4eff, some are with Brief Extension Word
switch (xn) {
case 0: // 4eb8 / 4ef8 (xxx).W
- {
+ if (node.offset + kInstructionSizeStepBytes < code.occupied_size) {
node.size = kInstructionSizeStepBytes * 2;
// This shit is real: it is sign extend value
const int32_t dispmt = GetI16BE(code.buffer + node.offset + kInstructionSizeStepBytes);
@@ -85,8 +92,9 @@ static void disasm_jsr_jmp(
snprintf(node.arguments, kArgsBufferSize, "0x%x:w", dispmt);
return;
}
+ break;
case 1: // 4eb9 / 4ef9 (xxx).L
- {
+ if (node.offset + kInstructionSizeStepBytes < code.occupied_size) {
node.size = kInstructionSizeStepBytes * 3;
const int32_t dispmt = GetI32BE(code.buffer + node.offset + kInstructionSizeStepBytes);
const uint32_t branch_addr = static_cast<uint32_t>(dispmt);
@@ -97,8 +105,9 @@ static void disasm_jsr_jmp(
snprintf(node.arguments, kArgsBufferSize, "0x%x:l", dispmt);
return;
}
+ break;
case 2: // 4eba / 4efa, Displacement
- {
+ if (node.offset + kInstructionSizeStepBytes < code.occupied_size) {
const int16_t dispmt = GetI16BE(code.buffer + node.offset + kInstructionSizeStepBytes);
// Add 2 to current PC, as usual
const uint32_t branch_addr = static_cast<uint32_t>(
@@ -111,13 +120,19 @@ static void disasm_jsr_jmp(
snprintf(node.arguments, kArgsBufferSize, "%%pc@(%d:w)", dispmt);
return;
}
+ break;
case 3: // 4ebb / 4efb
- {
+ if (node.offset + kInstructionSizeStepBytes < code.occupied_size) {
// NOTE: dynamic jump, branch_addr may possibly be obtained
// during the trace
node.size = kInstructionSizeStepBytes * 2;
const uint16_t briefext = GetU16BE(
code.buffer + node.offset + kInstructionSizeStepBytes);
+ if (briefext & 0x0700) {
+ // briefext must have zeros on 8, 9 an 10-th bits,
+ // i.e. xxxx_x000_xxxx_xxxx
+ break;
+ }
const char reg = ((briefext >> 15) & 1) ? 'a' : 'd';
const int xn2 = (briefext >> 12) & 7;
const char size_spec = ((briefext >> 11) & 1) ? 'l' : 'w';
@@ -127,6 +142,7 @@ static void disasm_jsr_jmp(
"%%pc@(%d,%%%c%d:%c)", dispmt, reg, xn2, size_spec);
return;
}
+ break;
case 4: // 4ebc / 4efb
case 5: // 4ebd / 4efd
case 6: // 4ebe / 4efe
@@ -193,21 +209,27 @@ static inline const char *bcc_mnemonic_by_condition(Condition condition)
}
static void disasm_bra_bsr_bcc(
- DisasmNode& node, uint16_t instr, const DataBuffer &code, const Settings &)
+ DisasmNode& node, uint16_t instr, const DataBuffer &code, const Settings &s)
{
Condition condition = static_cast<Condition>((instr >> 8) & 0xf);
const char *mnemonic = bcc_mnemonic_by_condition(condition);
// False condition Indicates BSR
- node.is_call = (condition == Condition::kF);
int dispmt = static_cast<int8_t>(instr & 0xff);
+ if (dispmt % kInstructionSizeStepBytes) {
+ return disasm_verbatim(node, instr, code, s);
+ }
const char *size_spec = "s";
if (dispmt == 0) {
dispmt = GetI16BE(code.buffer + node.offset + kInstructionSizeStepBytes);
+ if (dispmt % kInstructionSizeStepBytes) {
+ return disasm_verbatim(node, instr, code, s);
+ }
node.size = kInstructionSizeStepBytes * 2;
size_spec = "w";
} else {
node.size = kInstructionSizeStepBytes;
}
+ node.is_call = (condition == Condition::kF);
dispmt += kInstructionSizeStepBytes;
const uint32_t branch_addr = static_cast<uint32_t>(node.offset + dispmt);
node.branch_addr = branch_addr;
@@ -330,47 +352,54 @@ static void disasm_addq_subq(
snprintf(node.arguments, kArgsBufferSize, "#%u,%%a%d@-", imm, xn);
return;
case 5: // 5x28..5x2f / 5x68..5x6f / 5xa8..5xaf, (d16, An), Displacement Word
- node.size = kInstructionSizeStepBytes * 2;
- snprintf(node.mnemonic, kMnemonicBufferSize, "%s%c", mnemonic, suffix);
- {
+ if (node.offset + kInstructionSizeStepBytes < code.occupied_size) {
+ node.size = kInstructionSizeStepBytes * 2;
+ snprintf(node.mnemonic, kMnemonicBufferSize, "%s%c", mnemonic, suffix);
const int16_t dispmt = GetI16BE(code.buffer + node.offset + kInstructionSizeStepBytes);
snprintf(node.arguments, kArgsBufferSize, "#%u,%%a%d@(%d:w)", imm, xn, dispmt);
+ return;
}
- return;
+ break;
case 6: // 5x30..5x37 / 5x70..5x77 / 5xb0..5xb7, (d16, An, Xi), Brief Extension Word
- node.size = kInstructionSizeStepBytes * 2;
- snprintf(node.mnemonic, kMnemonicBufferSize, "%s%c", mnemonic, suffix);
- {
+ if (node.offset + kInstructionSizeStepBytes < code.occupied_size) {
+ node.size = kInstructionSizeStepBytes * 2;
+ snprintf(node.mnemonic, kMnemonicBufferSize, "%s%c", mnemonic, suffix);
const uint16_t briefext = GetU16BE(code.buffer + node.offset + kInstructionSizeStepBytes);
+ if (briefext & 0x0700) {
+ // briefext must have zeros on 8, 9 an 10-th bits,
+ // i.e. xxxx_x000_xxxx_xxxx
+ break;
+ }
const char reg = ((briefext >> 15) & 1) ? 'a' : 'd';
const int xi = (briefext >> 12) & 7;
const char size_spec = ((briefext >> 11) & 1) ? 'l' : 'w';
const int8_t dispmt = briefext & 0xff;
snprintf(node.arguments, kArgsBufferSize,
"#%u,%%a%d@(%d,%%%c%d:%c)", imm, xn, dispmt, reg, xi, size_spec);
+ return;
}
- return;
+ break;
case 7: // 5x38..5x3f / 5x78..5x7f / 5xb8..5xbf
switch (xn) {
case 0: // 5x38 / 5x78 / 5xb8 (xxx).W
- node.size = kInstructionSizeStepBytes * 2;
- snprintf(node.mnemonic, kMnemonicBufferSize, "%s%c", mnemonic, suffix);
- {
+ if (node.offset + kInstructionSizeStepBytes < code.occupied_size) {
+ node.size = kInstructionSizeStepBytes * 2;
+ snprintf(node.mnemonic, kMnemonicBufferSize, "%s%c", mnemonic, suffix);
// This shit is real: it is sign extend value
const int32_t dispmt = GetI16BE(code.buffer + node.offset + kInstructionSizeStepBytes);
snprintf(node.arguments, kArgsBufferSize, "#%u,0x%x:w", imm, dispmt);
return;
}
- return;
+ break;
case 1: // 5x39 / 5x79 / 5xb9 (xxx).L
- node.size = kInstructionSizeStepBytes * 3;
- snprintf(node.mnemonic, kMnemonicBufferSize, "%s%c", mnemonic, suffix);
- {
+ if (node.offset + kInstructionSizeStepBytes < code.occupied_size) {
+ node.size = kInstructionSizeStepBytes * 3;
+ snprintf(node.mnemonic, kMnemonicBufferSize, "%s%c", mnemonic, suffix);
const int32_t dispmt = GetI32BE(code.buffer + node.offset + kInstructionSizeStepBytes);
snprintf(node.arguments, kArgsBufferSize, "#%u,0x%x:l", imm, dispmt);
return;
}
- return;
+ break;
case 2: // 5x3a / 5x7a / 5xba
case 3: // 5x3b / 5x7b / 5xbb
case 4: // 5x3c / 5x7c / 5xbc
@@ -439,47 +468,54 @@ static void disasm_scc(
snprintf(node.arguments, kArgsBufferSize, "%%a%d@-", xn);
return;
case 5: // 5xe8..5xef, (d16, An), Displacement Word
- node.size = kInstructionSizeStepBytes * 2;
- snprintf(node.mnemonic, kMnemonicBufferSize, mnemonic);
- {
+ if (node.offset + kInstructionSizeStepBytes < code.occupied_size) {
+ node.size = kInstructionSizeStepBytes * 2;
+ snprintf(node.mnemonic, kMnemonicBufferSize, mnemonic);
const int16_t dispmt = GetI16BE(code.buffer + node.offset + kInstructionSizeStepBytes);
snprintf(node.arguments, kArgsBufferSize, "%%a%d@(%d:w)", xn, dispmt);
+ return;
}
- return;
+ break;
case 6: // 5xf0..5xf7, (d16, An, Xi), Brief Extension Word
- node.size = kInstructionSizeStepBytes * 2;
- snprintf(node.mnemonic, kMnemonicBufferSize, mnemonic);
- {
+ if (node.offset + kInstructionSizeStepBytes < code.occupied_size) {
+ node.size = kInstructionSizeStepBytes * 2;
+ snprintf(node.mnemonic, kMnemonicBufferSize, mnemonic);
const uint16_t briefext = GetU16BE(code.buffer + node.offset + kInstructionSizeStepBytes);
+ if (briefext & 0x0700) {
+ // briefext must have zeros on 8, 9 an 10-th bits,
+ // i.e. xxxx_x000_xxxx_xxxx
+ break;
+ }
const char reg = ((briefext >> 15) & 1) ? 'a' : 'd';
const int xi = (briefext >> 12) & 7;
const char size_spec = ((briefext >> 11) & 1) ? 'l' : 'w';
const int8_t dispmt = briefext & 0xff;
snprintf(node.arguments, kArgsBufferSize,
"%%a%d@(%d,%%%c%d:%c)", xn, dispmt, reg, xi, size_spec);
+ return;
}
- return;
+ break;
case 7: // 5xf8..5xff
switch (xn) {
case 0: // 5xf8 (xxx).W
node.size = kInstructionSizeStepBytes * 2;
snprintf(node.mnemonic, kMnemonicBufferSize, mnemonic);
- {
+ if (node.offset + kInstructionSizeStepBytes < code.occupied_size) {
// This shit is real: it is sign extend value
const int32_t dispmt = GetI16BE(code.buffer + node.offset + kInstructionSizeStepBytes);
snprintf(node.arguments, kArgsBufferSize, "0x%x:w", dispmt);
return;
}
- return;
+ break;
case 1: // 5xf9 (xxx).L
node.size = kInstructionSizeStepBytes * 3;
snprintf(node.mnemonic, kMnemonicBufferSize, mnemonic);
- {
+ if (node.offset + kInstructionSizeStepBytes < code.occupied_size) {
const int32_t dispmt = GetI32BE(code.buffer + node.offset + kInstructionSizeStepBytes);
snprintf(node.arguments, kArgsBufferSize, "0x%x:l", dispmt);
return;
}
- return;
+ break;
case 2: // 5xfa
case 3: // 5xfb
case 4: // 5xfc
@@ -517,17 +553,23 @@ static inline const char *dbcc_mnemonic_by_condition(Condition condition)
return "?";
}
-static void disasm_dbcc(DisasmNode& node, uint16_t instr, const DataBuffer &code, const Settings &)
+static void disasm_dbcc(DisasmNode& node, uint16_t instr, const DataBuffer &code, const Settings &s)
{
+ if (node.offset + kInstructionSizeStepBytes >= code.occupied_size) {
+ return disasm_verbatim(node, instr, code, s);
+ }
+ const int16_t dispmt_raw = GetI16BE(code.buffer + node.offset + kInstructionSizeStepBytes);
+ if (dispmt_raw % kInstructionSizeStepBytes) {
+ return disasm_verbatim(node, instr, code, s);
+ }
node.size = kInstructionSizeStepBytes * 2;
Condition condition = static_cast<Condition>((instr >> 8) & 0xf);
const char *mnemonic = dbcc_mnemonic_by_condition(condition);
const int dn = (instr & 7);
- int16_t dispmt = GetI16BE(code.buffer + node.offset + kInstructionSizeStepBytes);
- const uint32_t branch_addr = static_cast<uint32_t>(node.offset + dispmt);
+ const uint32_t branch_addr = static_cast<uint32_t>(node.offset + dispmt_raw);
node.branch_addr = branch_addr;
node.has_branch_addr = true;
- dispmt += kInstructionSizeStepBytes;
+ const int16_t dispmt = dispmt_raw + kInstructionSizeStepBytes;
snprintf(node.mnemonic, kMnemonicBufferSize, "%s", mnemonic);
const char * const sign = dispmt >= 0 ? "+" : "";
// FIXME support s.rel_marks option for this instruction
diff --git a/test_random.bash b/test_random.bash
index 81c8295..0939e24 100644
--- a/test_random.bash
+++ b/test_random.bash
@@ -20,6 +20,7 @@ mkdir -p ${TEST_DIR}
run_test_random() {
local pass_number=$1
+ local blocks_count=$2
local test_name_sanitized=${pass_number//[^a-zA-Z0-9_\-]/-}
local file_orig_bin=${TEST_DIR}/${test_name_sanitized}.orig.bin
local file_asm=${TEST_DIR}/${test_name_sanitized}.S
@@ -27,15 +28,18 @@ run_test_random() {
local file_as_elf=${TEST_DIR}/${test_name_sanitized}.as.elf
local file_as_bin=${TEST_DIR}/${test_name_sanitized}.as.bin
echo -ne "Test random, pass ${pass_number}... "
- dd if=/dev/urandom of=${file_orig_bin} bs=1024 count=1
+ dd if=/dev/urandom of=${file_orig_bin} bs=1024 count=${blocks_count} >/dev/null 2>&1
${DISASM} -o ${file_asm} ${file_orig_bin}
${AS} -o ${file_as_o} ${file_asm}
${LD} -o ${file_as_elf} ${file_as_o}
${OBJCOPY} ${file_as_elf} -O binary ${file_as_bin}
- if ! cmp ${file_orig_bin} ${file_as_bin} >/dev/null 2>&1; then
+ if ! cmp ${file_orig_bin} ${file_as_bin}; then
echo -e "${CRED}FAIL${CRST}: output and input binaries do not match"
+ hexdump -Cv ${file_orig_bin} >${file_orig_bin}.txt
+ hexdump -Cv ${file_as_bin} >${file_as_bin}.txt
echo ${file_orig_bin}
echo ${file_as_bin}
+ exit
else
echo -e "${CGREEN}OK${CRST}"
#cat ${file_asm}
@@ -43,5 +47,9 @@ run_test_random() {
}
for i in `seq 1 10`; do
- run_test_random $i
+ run_test_random huge$i 1024
+done
+
+for i in `seq 1 1000`; do
+ run_test_random tiny$i 1
done