mirror of https://github.com/mgba-emu/mgba.git
ARM Debugger: Disassembler now resolves addresses to symbol names
This commit is contained in:
parent
17ca8f524a
commit
87ec3f3d4a
1
CHANGES
1
CHANGES
|
@ -9,6 +9,7 @@ Features:
|
||||||
- New unlicensed GB mappers: Pokémon Jade/Diamond, BBD, and Hitek
|
- New unlicensed GB mappers: Pokémon Jade/Diamond, BBD, and Hitek
|
||||||
- Stack tracing tools in ARM debugger (by ahigerd)
|
- Stack tracing tools in ARM debugger (by ahigerd)
|
||||||
- Command scripts for CLI debugger (by ahigerd)
|
- Command scripts for CLI debugger (by ahigerd)
|
||||||
|
- ARM disassembler now resolves addresses to symbol names
|
||||||
Emulation fixes:
|
Emulation fixes:
|
||||||
- ARM: Fix ALU reading PC after shifting
|
- ARM: Fix ALU reading PC after shifting
|
||||||
- ARM: Fix STR storing PC after address calculation
|
- ARM: Fix STR storing PC after address calculation
|
||||||
|
|
|
@ -212,11 +212,12 @@ struct ARMInstructionInfo {
|
||||||
unsigned nDataCycles : 10;
|
unsigned nDataCycles : 10;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct mDebuggerSymbols;
|
||||||
void ARMDecodeARM(uint32_t opcode, struct ARMInstructionInfo* info);
|
void ARMDecodeARM(uint32_t opcode, struct ARMInstructionInfo* info);
|
||||||
void ARMDecodeThumb(uint16_t opcode, struct ARMInstructionInfo* info);
|
void ARMDecodeThumb(uint16_t opcode, struct ARMInstructionInfo* info);
|
||||||
bool ARMDecodeThumbCombine(struct ARMInstructionInfo* info1, struct ARMInstructionInfo* info2,
|
bool ARMDecodeThumbCombine(struct ARMInstructionInfo* info1, struct ARMInstructionInfo* info2,
|
||||||
struct ARMInstructionInfo* out);
|
struct ARMInstructionInfo* out);
|
||||||
int ARMDisassemble(struct ARMInstructionInfo* info, uint32_t pc, char* buffer, int blen);
|
int ARMDisassemble(struct ARMInstructionInfo* info, struct ARMCore* core, const struct mDebuggerSymbols* symbols, uint32_t pc, char* buffer, int blen);
|
||||||
uint32_t ARMResolveMemoryAccess(struct ARMInstructionInfo* info, struct ARMRegisterFile* regs, uint32_t pc);
|
uint32_t ARMResolveMemoryAccess(struct ARMInstructionInfo* info, struct ARMRegisterFile* regs, uint32_t pc);
|
||||||
|
|
||||||
CXX_GUARD_END
|
CXX_GUARD_END
|
||||||
|
|
|
@ -98,28 +98,29 @@ static void _disassembleMode(struct CLIDebugger* debugger, struct CLIDebugVector
|
||||||
|
|
||||||
static inline uint32_t _printLine(struct CLIDebugger* debugger, uint32_t address, enum ExecutionMode mode) {
|
static inline uint32_t _printLine(struct CLIDebugger* debugger, uint32_t address, enum ExecutionMode mode) {
|
||||||
struct CLIDebuggerBackend* be = debugger->backend;
|
struct CLIDebuggerBackend* be = debugger->backend;
|
||||||
|
struct mCore* core = debugger->d.core;
|
||||||
char disassembly[64];
|
char disassembly[64];
|
||||||
struct ARMInstructionInfo info;
|
struct ARMInstructionInfo info;
|
||||||
be->printf(be, "%08X: ", address);
|
be->printf(be, "%08X: ", address);
|
||||||
if (mode == MODE_ARM) {
|
if (mode == MODE_ARM) {
|
||||||
uint32_t instruction = debugger->d.core->busRead32(debugger->d.core, address);
|
uint32_t instruction = core->busRead32(core, address);
|
||||||
ARMDecodeARM(instruction, &info);
|
ARMDecodeARM(instruction, &info);
|
||||||
ARMDisassemble(&info, address + WORD_SIZE_ARM * 2, disassembly, sizeof(disassembly));
|
ARMDisassemble(&info, core->cpu, core->symbolTable, address + WORD_SIZE_ARM * 2, disassembly, sizeof(disassembly));
|
||||||
be->printf(be, "%08X\t%s\n", instruction, disassembly);
|
be->printf(be, "%08X\t%s\n", instruction, disassembly);
|
||||||
return WORD_SIZE_ARM;
|
return WORD_SIZE_ARM;
|
||||||
} else {
|
} else {
|
||||||
struct ARMInstructionInfo info2;
|
struct ARMInstructionInfo info2;
|
||||||
struct ARMInstructionInfo combined;
|
struct ARMInstructionInfo combined;
|
||||||
uint16_t instruction = debugger->d.core->busRead16(debugger->d.core, address);
|
uint16_t instruction = core->busRead16(core, address);
|
||||||
uint16_t instruction2 = debugger->d.core->busRead16(debugger->d.core, address + WORD_SIZE_THUMB);
|
uint16_t instruction2 = core->busRead16(core, address + WORD_SIZE_THUMB);
|
||||||
ARMDecodeThumb(instruction, &info);
|
ARMDecodeThumb(instruction, &info);
|
||||||
ARMDecodeThumb(instruction2, &info2);
|
ARMDecodeThumb(instruction2, &info2);
|
||||||
if (ARMDecodeThumbCombine(&info, &info2, &combined)) {
|
if (ARMDecodeThumbCombine(&info, &info2, &combined)) {
|
||||||
ARMDisassemble(&combined, address + WORD_SIZE_THUMB * 2, disassembly, sizeof(disassembly));
|
ARMDisassemble(&combined, core->cpu, core->symbolTable, address + WORD_SIZE_THUMB * 2, disassembly, sizeof(disassembly));
|
||||||
be->printf(be, "%04X %04X\t%s\n", instruction, instruction2, disassembly);
|
be->printf(be, "%04X %04X\t%s\n", instruction, instruction2, disassembly);
|
||||||
return WORD_SIZE_THUMB * 2;
|
return WORD_SIZE_THUMB * 2;
|
||||||
} else {
|
} else {
|
||||||
ARMDisassemble(&info, address + WORD_SIZE_THUMB * 2, disassembly, sizeof(disassembly));
|
ARMDisassemble(&info, core->cpu, core->symbolTable, address + WORD_SIZE_THUMB * 2, disassembly, sizeof(disassembly));
|
||||||
be->printf(be, "%04X \t%s\n", instruction, disassembly);
|
be->printf(be, "%04X \t%s\n", instruction, disassembly);
|
||||||
return WORD_SIZE_THUMB;
|
return WORD_SIZE_THUMB;
|
||||||
}
|
}
|
||||||
|
|
|
@ -467,6 +467,7 @@ static void ARMDebuggerListWatchpoints(struct mDebuggerPlatform* d, struct mWatc
|
||||||
static void ARMDebuggerTrace(struct mDebuggerPlatform* d, char* out, size_t* length) {
|
static void ARMDebuggerTrace(struct mDebuggerPlatform* d, char* out, size_t* length) {
|
||||||
struct ARMDebugger* debugger = (struct ARMDebugger*) d;
|
struct ARMDebugger* debugger = (struct ARMDebugger*) d;
|
||||||
struct ARMCore* cpu = debugger->cpu;
|
struct ARMCore* cpu = debugger->cpu;
|
||||||
|
struct mCore* core = d->p->core;
|
||||||
|
|
||||||
char disassembly[64];
|
char disassembly[64];
|
||||||
|
|
||||||
|
@ -475,17 +476,17 @@ static void ARMDebuggerTrace(struct mDebuggerPlatform* d, char* out, size_t* len
|
||||||
if (cpu->executionMode == MODE_ARM) {
|
if (cpu->executionMode == MODE_ARM) {
|
||||||
uint32_t instruction = cpu->prefetch[0];
|
uint32_t instruction = cpu->prefetch[0];
|
||||||
sprintf(disassembly, "%08X: ", instruction);
|
sprintf(disassembly, "%08X: ", instruction);
|
||||||
ARMDisassemble(&info, cpu->gprs[ARM_PC], disassembly + strlen("00000000: "), sizeof(disassembly) - strlen("00000000: "));
|
ARMDisassemble(&info, cpu, core->symbolTable, cpu->gprs[ARM_PC], disassembly + strlen("00000000: "), sizeof(disassembly) - strlen("00000000: "));
|
||||||
} else {
|
} else {
|
||||||
uint16_t instruction = cpu->prefetch[0];
|
uint16_t instruction = cpu->prefetch[0];
|
||||||
ARMDecodeThumb(instruction, &info);
|
ARMDecodeThumb(instruction, &info);
|
||||||
if (isWideInstruction) {
|
if (isWideInstruction) {
|
||||||
uint16_t instruction2 = cpu->prefetch[1];
|
uint16_t instruction2 = cpu->prefetch[1];
|
||||||
sprintf(disassembly, "%04X%04X: ", instruction, instruction2);
|
sprintf(disassembly, "%04X%04X: ", instruction, instruction2);
|
||||||
ARMDisassemble(&info, cpu->gprs[ARM_PC], disassembly + strlen("00000000: "), sizeof(disassembly) - strlen("00000000: "));
|
ARMDisassemble(&info, cpu, core->symbolTable, cpu->gprs[ARM_PC], disassembly + strlen("00000000: "), sizeof(disassembly) - strlen("00000000: "));
|
||||||
} else {
|
} else {
|
||||||
sprintf(disassembly, " %04X: ", instruction);
|
sprintf(disassembly, " %04X: ", instruction);
|
||||||
ARMDisassemble(&info, cpu->gprs[ARM_PC], disassembly + strlen("00000000: "), sizeof(disassembly) - strlen("00000000: "));
|
ARMDisassemble(&info, cpu, core->symbolTable, cpu->gprs[ARM_PC], disassembly + strlen("00000000: "), sizeof(disassembly) - strlen("00000000: "));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include <mgba/internal/arm/decoder.h>
|
#include <mgba/internal/arm/decoder.h>
|
||||||
|
|
||||||
#include <mgba/internal/arm/decoder-inlines.h>
|
#include <mgba/internal/arm/decoder-inlines.h>
|
||||||
|
#include <mgba/internal/debugger/symbols.h>
|
||||||
#include <mgba-util/string.h>
|
#include <mgba-util/string.h>
|
||||||
|
|
||||||
#define ADVANCE(AMOUNT) \
|
#define ADVANCE(AMOUNT) \
|
||||||
|
@ -20,8 +21,8 @@
|
||||||
static int _decodeRegister(int reg, char* buffer, int blen);
|
static int _decodeRegister(int reg, char* buffer, int blen);
|
||||||
static int _decodeRegisterList(int list, char* buffer, int blen);
|
static int _decodeRegisterList(int list, char* buffer, int blen);
|
||||||
static int _decodePSR(int bits, char* buffer, int blen);
|
static int _decodePSR(int bits, char* buffer, int blen);
|
||||||
static int _decodePCRelative(uint32_t address, uint32_t pc, char* buffer, int blen);
|
static int _decodePCRelative(uint32_t address, const struct mDebuggerSymbols* symbols, uint32_t pc, bool thumbBranch, char* buffer, int blen);
|
||||||
static int _decodeMemory(struct ARMMemoryAccess memory, int pc, char* buffer, int blen);
|
static int _decodeMemory(struct ARMMemoryAccess memory, struct ARMCore* cpu, const struct mDebuggerSymbols* symbols, int pc, char* buffer, int blen);
|
||||||
static int _decodeShift(union ARMOperand operand, bool reg, char* buffer, int blen);
|
static int _decodeShift(union ARMOperand operand, bool reg, char* buffer, int blen);
|
||||||
|
|
||||||
static const char* _armConditions[] = {
|
static const char* _armConditions[] = {
|
||||||
|
@ -141,23 +142,66 @@ static int _decodePSR(int psrBits, char* buffer, int blen) {
|
||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _decodePCRelative(uint32_t address, uint32_t pc, char* buffer, int blen) {
|
static int _decodePCRelative(uint32_t address, const struct mDebuggerSymbols* symbols, uint32_t pc, bool thumbBranch, char* buffer, int blen) {
|
||||||
return snprintf(buffer, blen, "$%08X", address + pc);
|
address += pc;
|
||||||
|
const char* label = NULL;
|
||||||
|
if (symbols) {
|
||||||
|
label = mDebuggerSymbolReverseLookup(symbols, address, -1);
|
||||||
|
if (!label && thumbBranch) {
|
||||||
|
label = mDebuggerSymbolReverseLookup(symbols, address | 1, -1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (label) {
|
||||||
|
return strlcpy(buffer, label, blen);
|
||||||
|
} else {
|
||||||
|
return snprintf(buffer, blen, "0x%08X", address);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _decodeMemory(struct ARMMemoryAccess memory, int pc, char* buffer, int blen) {
|
static int _decodeMemory(struct ARMMemoryAccess memory, struct ARMCore* cpu, const struct mDebuggerSymbols* symbols, int pc, char* buffer, int blen) {
|
||||||
if (blen <= 1) {
|
if (blen <= 1) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
int total = 0;
|
int total = 0;
|
||||||
strlcpy(buffer, "[", blen);
|
bool elideClose = false;
|
||||||
ADVANCE(1);
|
|
||||||
int written;
|
int written;
|
||||||
if (memory.format & ARM_MEMORY_REGISTER_BASE) {
|
if (memory.format & ARM_MEMORY_REGISTER_BASE) {
|
||||||
if (memory.baseReg == ARM_PC && memory.format & ARM_MEMORY_IMMEDIATE_OFFSET) {
|
if (memory.baseReg == ARM_PC && memory.format & ARM_MEMORY_IMMEDIATE_OFFSET) {
|
||||||
written = _decodePCRelative(memory.format & ARM_MEMORY_OFFSET_SUBTRACT ? -memory.offset.immediate : memory.offset.immediate, pc & 0xFFFFFFFC, buffer, blen);
|
uint32_t addrBase = memory.format & ARM_MEMORY_OFFSET_SUBTRACT ? -memory.offset.immediate : memory.offset.immediate;
|
||||||
ADVANCE(written);
|
if (!cpu) {
|
||||||
|
strlcpy(buffer, "[", blen);
|
||||||
|
ADVANCE(1);
|
||||||
|
written = _decodePCRelative(addrBase, symbols, pc & 0xFFFFFFFC, false, buffer, blen);
|
||||||
|
ADVANCE(written);
|
||||||
|
} else {
|
||||||
|
uint32_t value;
|
||||||
|
addrBase += pc & 0xFFFFFFFC; // Thumb does not have PC-relative LDRH/LDRB
|
||||||
|
switch (memory.width & 7) {
|
||||||
|
case 1:
|
||||||
|
value = cpu->memory.load8(cpu, addrBase, NULL);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
value = cpu->memory.load16(cpu, addrBase, NULL);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
value = cpu->memory.load32(cpu, addrBase, NULL);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
const char* label = NULL;
|
||||||
|
if (symbols) {
|
||||||
|
label = mDebuggerSymbolReverseLookup(symbols, value, -1);
|
||||||
|
}
|
||||||
|
if (label) {
|
||||||
|
written = snprintf(buffer, blen, "=%s", label);
|
||||||
|
} else {
|
||||||
|
written = snprintf(buffer, blen, "=0x%08X", value);
|
||||||
|
}
|
||||||
|
ADVANCE(written);
|
||||||
|
elideClose = true;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
|
strlcpy(buffer, "[", blen);
|
||||||
|
ADVANCE(1);
|
||||||
written = _decodeRegister(memory.baseReg, buffer, blen);
|
written = _decodeRegister(memory.baseReg, buffer, blen);
|
||||||
ADVANCE(written);
|
ADVANCE(written);
|
||||||
if (memory.format & (ARM_MEMORY_REGISTER_OFFSET | ARM_MEMORY_IMMEDIATE_OFFSET) && !(memory.format & ARM_MEMORY_POST_INCREMENT)) {
|
if (memory.format & (ARM_MEMORY_REGISTER_OFFSET | ARM_MEMORY_IMMEDIATE_OFFSET) && !(memory.format & ARM_MEMORY_POST_INCREMENT)) {
|
||||||
|
@ -165,10 +209,14 @@ static int _decodeMemory(struct ARMMemoryAccess memory, int pc, char* buffer, in
|
||||||
ADVANCE(2);
|
ADVANCE(2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
strlcpy(buffer, "[", blen);
|
||||||
|
ADVANCE(1);
|
||||||
}
|
}
|
||||||
if (memory.format & ARM_MEMORY_POST_INCREMENT) {
|
if (memory.format & ARM_MEMORY_POST_INCREMENT) {
|
||||||
strlcpy(buffer, "], ", blen);
|
strlcpy(buffer, "], ", blen);
|
||||||
ADVANCE(3);
|
ADVANCE(3);
|
||||||
|
elideClose = true;
|
||||||
}
|
}
|
||||||
if (memory.format & ARM_MEMORY_IMMEDIATE_OFFSET && memory.baseReg != ARM_PC) {
|
if (memory.format & ARM_MEMORY_IMMEDIATE_OFFSET && memory.baseReg != ARM_PC) {
|
||||||
if (memory.format & ARM_MEMORY_OFFSET_SUBTRACT) {
|
if (memory.format & ARM_MEMORY_OFFSET_SUBTRACT) {
|
||||||
|
@ -191,7 +239,7 @@ static int _decodeMemory(struct ARMMemoryAccess memory, int pc, char* buffer, in
|
||||||
ADVANCE(written);
|
ADVANCE(written);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(memory.format & ARM_MEMORY_POST_INCREMENT)) {
|
if (!elideClose) {
|
||||||
strlcpy(buffer, "]", blen);
|
strlcpy(buffer, "]", blen);
|
||||||
ADVANCE(1);
|
ADVANCE(1);
|
||||||
}
|
}
|
||||||
|
@ -322,7 +370,7 @@ static const char* _armAccessTypeStrings[] = {
|
||||||
""
|
""
|
||||||
};
|
};
|
||||||
|
|
||||||
int ARMDisassemble(struct ARMInstructionInfo* info, uint32_t pc, char* buffer, int blen) {
|
int ARMDisassemble(struct ARMInstructionInfo* info, struct ARMCore* cpu, const struct mDebuggerSymbols* symbols, uint32_t pc, char* buffer, int blen) {
|
||||||
const char* mnemonic = _armMnemonicStrings[info->mnemonic];
|
const char* mnemonic = _armMnemonicStrings[info->mnemonic];
|
||||||
int written;
|
int written;
|
||||||
int total = 0;
|
int total = 0;
|
||||||
|
@ -394,7 +442,7 @@ int ARMDisassemble(struct ARMInstructionInfo* info, uint32_t pc, char* buffer, i
|
||||||
case ARM_MN_B:
|
case ARM_MN_B:
|
||||||
case ARM_MN_BL:
|
case ARM_MN_BL:
|
||||||
if (info->operandFormat & ARM_OPERAND_IMMEDIATE_1) {
|
if (info->operandFormat & ARM_OPERAND_IMMEDIATE_1) {
|
||||||
written = _decodePCRelative(info->op1.immediate, pc, buffer, blen);
|
written = _decodePCRelative(info->op1.immediate, symbols, pc, true, buffer, blen);
|
||||||
ADVANCE(written);
|
ADVANCE(written);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -403,7 +451,7 @@ int ARMDisassemble(struct ARMInstructionInfo* info, uint32_t pc, char* buffer, i
|
||||||
written = snprintf(buffer, blen, "#%i", info->op1.immediate);
|
written = snprintf(buffer, blen, "#%i", info->op1.immediate);
|
||||||
ADVANCE(written);
|
ADVANCE(written);
|
||||||
} else if (info->operandFormat & ARM_OPERAND_MEMORY_1) {
|
} else if (info->operandFormat & ARM_OPERAND_MEMORY_1) {
|
||||||
written = _decodeMemory(info->memory, pc, buffer, blen);
|
written = _decodeMemory(info->memory, cpu, symbols, pc, buffer, blen);
|
||||||
ADVANCE(written);
|
ADVANCE(written);
|
||||||
} else if (info->operandFormat & ARM_OPERAND_REGISTER_1) {
|
} else if (info->operandFormat & ARM_OPERAND_REGISTER_1) {
|
||||||
written = _decodeRegister(info->op1.reg, buffer, blen);
|
written = _decodeRegister(info->op1.reg, buffer, blen);
|
||||||
|
@ -428,7 +476,7 @@ int ARMDisassemble(struct ARMInstructionInfo* info, uint32_t pc, char* buffer, i
|
||||||
written = snprintf(buffer, blen, "#%i", info->op2.immediate);
|
written = snprintf(buffer, blen, "#%i", info->op2.immediate);
|
||||||
ADVANCE(written);
|
ADVANCE(written);
|
||||||
} else if (info->operandFormat & ARM_OPERAND_MEMORY_2) {
|
} else if (info->operandFormat & ARM_OPERAND_MEMORY_2) {
|
||||||
written = _decodeMemory(info->memory, pc, buffer, blen);
|
written = _decodeMemory(info->memory, cpu, symbols, pc, buffer, blen);
|
||||||
ADVANCE(written);
|
ADVANCE(written);
|
||||||
} else if (info->operandFormat & ARM_OPERAND_REGISTER_2) {
|
} else if (info->operandFormat & ARM_OPERAND_REGISTER_2) {
|
||||||
written = _decodeRegister(info->op2.reg, buffer, blen);
|
written = _decodeRegister(info->op2.reg, buffer, blen);
|
||||||
|
@ -449,7 +497,7 @@ int ARMDisassemble(struct ARMInstructionInfo* info, uint32_t pc, char* buffer, i
|
||||||
written = snprintf(buffer, blen, "#%i", info->op3.immediate);
|
written = snprintf(buffer, blen, "#%i", info->op3.immediate);
|
||||||
ADVANCE(written);
|
ADVANCE(written);
|
||||||
} else if (info->operandFormat & ARM_OPERAND_MEMORY_3) {
|
} else if (info->operandFormat & ARM_OPERAND_MEMORY_3) {
|
||||||
written = _decodeMemory(info->memory, pc, buffer, blen);
|
written = _decodeMemory(info->memory, cpu, symbols, pc, buffer, blen);
|
||||||
ADVANCE(written);
|
ADVANCE(written);
|
||||||
} else if (info->operandFormat & ARM_OPERAND_REGISTER_3) {
|
} else if (info->operandFormat & ARM_OPERAND_REGISTER_3) {
|
||||||
written = _decodeRegister(info->op3.reg, buffer, blen);
|
written = _decodeRegister(info->op3.reg, buffer, blen);
|
||||||
|
@ -470,7 +518,7 @@ int ARMDisassemble(struct ARMInstructionInfo* info, uint32_t pc, char* buffer, i
|
||||||
written = snprintf(buffer, blen, "#%i", info->op4.immediate);
|
written = snprintf(buffer, blen, "#%i", info->op4.immediate);
|
||||||
ADVANCE(written);
|
ADVANCE(written);
|
||||||
} else if (info->operandFormat & ARM_OPERAND_MEMORY_4) {
|
} else if (info->operandFormat & ARM_OPERAND_MEMORY_4) {
|
||||||
written = _decodeMemory(info->memory, pc, buffer, blen);
|
written = _decodeMemory(info->memory, cpu, symbols, pc, buffer, blen);
|
||||||
ADVANCE(written);
|
ADVANCE(written);
|
||||||
} else if (info->operandFormat & ARM_OPERAND_REGISTER_4) {
|
} else if (info->operandFormat & ARM_OPERAND_REGISTER_4) {
|
||||||
written = _decodeRegister(info->op4.reg, buffer, blen);
|
written = _decodeRegister(info->op4.reg, buffer, blen);
|
||||||
|
|
Loading…
Reference in New Issue