mirror of
https://github.com/lifegpc/msg-tool.git
synced 2026-07-08 01:31:53 +08:00
Handle more choices in totsulover
Allow to trace choice syscall in user function
This commit is contained in:
@@ -241,7 +241,7 @@ const TEXT_CAT: u16 = 0x0099;
|
|||||||
pub const CODE_OFFSET: u32 = 0xC;
|
pub const CODE_OFFSET: u32 = 0xC;
|
||||||
const BIN_XOR: u16 = 0x0008;
|
const BIN_XOR: u16 = 0x0008;
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
struct Operand {
|
struct Operand {
|
||||||
offset: u32,
|
offset: u32,
|
||||||
raw_value: u32,
|
raw_value: u32,
|
||||||
@@ -309,10 +309,16 @@ struct UserMessageFunction {
|
|||||||
message_arg_index: u32,
|
message_arg_index: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct UserChoiceFunction {
|
||||||
|
num_args: u32,
|
||||||
|
choice_arg_indexs: Vec<u32>,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Disasm<'a> {
|
pub struct Disasm<'a> {
|
||||||
reader: MemReaderRef<'a>,
|
reader: MemReaderRef<'a>,
|
||||||
label_offsets: Vec<u32>,
|
label_offsets: Vec<u32>,
|
||||||
user_message_functions: HashMap<u32, UserMessageFunction>,
|
user_message_functions: HashMap<u32, UserMessageFunction>,
|
||||||
|
user_choice_functions: HashMap<u32, UserChoiceFunction>,
|
||||||
variables: HashMap<u32, Operand>,
|
variables: HashMap<u32, Operand>,
|
||||||
stack: Vec<Operand>,
|
stack: Vec<Operand>,
|
||||||
strs: Vec<PalString>,
|
strs: Vec<PalString>,
|
||||||
@@ -359,6 +365,7 @@ impl<'a> Disasm<'a> {
|
|||||||
reader,
|
reader,
|
||||||
label_offsets: label_offsets.to_vec(),
|
label_offsets: label_offsets.to_vec(),
|
||||||
user_message_functions: HashMap::new(),
|
user_message_functions: HashMap::new(),
|
||||||
|
user_choice_functions: HashMap::new(),
|
||||||
variables: HashMap::new(),
|
variables: HashMap::new(),
|
||||||
stack: Vec::new(),
|
stack: Vec::new(),
|
||||||
strs: Vec::new(),
|
strs: Vec::new(),
|
||||||
@@ -373,7 +380,7 @@ impl<'a> Disasm<'a> {
|
|||||||
mut self,
|
mut self,
|
||||||
mut writer: Option<&mut W>,
|
mut writer: Option<&mut W>,
|
||||||
) -> Result<Vec<PalString>> {
|
) -> Result<Vec<PalString>> {
|
||||||
self.find_user_message_functions()?;
|
self.find_user_functions()?;
|
||||||
self.reader.pos = CODE_OFFSET as usize;
|
self.reader.pos = CODE_OFFSET as usize;
|
||||||
let len = self.reader.data.len();
|
let len = self.reader.data.len();
|
||||||
while self.reader.pos < len {
|
while self.reader.pos < len {
|
||||||
@@ -513,9 +520,10 @@ impl<'a> Disasm<'a> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_user_message_functions(&mut self) -> Result<()> {
|
fn find_user_functions(&mut self) -> Result<()> {
|
||||||
let mut current_func_args = None;
|
let mut current_func_args = None;
|
||||||
self.reader.pos = CODE_OFFSET as usize;
|
self.reader.pos = CODE_OFFSET as usize;
|
||||||
|
let mut choice_indexes = Vec::new();
|
||||||
let len = self.reader.data.len();
|
let len = self.reader.data.len();
|
||||||
while self.reader.pos < len {
|
while self.reader.pos < len {
|
||||||
let instr = self.read_instruction()?;
|
let instr = self.read_instruction()?;
|
||||||
@@ -543,12 +551,34 @@ impl<'a> Disasm<'a> {
|
|||||||
self.stack.clear();
|
self.stack.clear();
|
||||||
// self.variables.clear();
|
// self.variables.clear();
|
||||||
continue;
|
continue;
|
||||||
|
} else if instr.opcode == SYSCALL && instr.operands[0].raw_value == 0x60002 {
|
||||||
|
let choice = self
|
||||||
|
.stack
|
||||||
|
.pop()
|
||||||
|
.ok_or_else(|| anyhow::anyhow!("No choice for choice sys call"))?;
|
||||||
|
if choice.typ() == OperandType::Argument {
|
||||||
|
choice_indexes.push(choice.value() - 1);
|
||||||
|
}
|
||||||
|
self.stack.clear();
|
||||||
|
if !choice_indexes.is_empty() {
|
||||||
|
if let Some((func_offset, func_num_args)) = current_func_args {
|
||||||
|
self.user_choice_functions.insert(
|
||||||
|
func_offset,
|
||||||
|
UserChoiceFunction {
|
||||||
|
num_args: func_num_args,
|
||||||
|
choice_arg_indexs: choice_indexes.clone(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
match instr.opcode {
|
match instr.opcode {
|
||||||
ENTER => {
|
ENTER => {
|
||||||
current_func_args = Some((instr.offset, instr.operands[0].value()));
|
current_func_args = Some((instr.offset, instr.operands[0].value()));
|
||||||
self.stack.clear();
|
self.stack.clear();
|
||||||
self.variables.clear(); // Safe to clear here, entering a new function frame
|
self.variables.clear(); // Safe to clear here, entering a new function frame
|
||||||
|
choice_indexes.clear();
|
||||||
}
|
}
|
||||||
MOV => {
|
MOV => {
|
||||||
self.handle_mov_instruction(instr)?;
|
self.handle_mov_instruction(instr)?;
|
||||||
@@ -560,6 +590,7 @@ impl<'a> Disasm<'a> {
|
|||||||
current_func_args = None;
|
current_func_args = None;
|
||||||
self.stack.clear();
|
self.stack.clear();
|
||||||
self.variables.clear(); // Safe to clear here, leaving function frame
|
self.variables.clear(); // Safe to clear here, leaving function frame
|
||||||
|
choice_indexes.clear();
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
self.stack.clear();
|
self.stack.clear();
|
||||||
@@ -635,6 +666,26 @@ impl<'a> Disasm<'a> {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
let target_offset = self.label_offsets[instr.operands[0].value() as usize - 1];
|
let target_offset = self.label_offsets[instr.operands[0].value() as usize - 1];
|
||||||
|
if let Some(func) = self.user_choice_functions.get(&target_offset) {
|
||||||
|
if self.stack.len() < func.num_args as usize {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
let mut args = Vec::new();
|
||||||
|
for _ in 0..func.num_args {
|
||||||
|
args.push(self.stack.pop().unwrap());
|
||||||
|
}
|
||||||
|
args.reverse();
|
||||||
|
for ind in &func.choice_arg_indexs {
|
||||||
|
let arg = &args[*ind as usize];
|
||||||
|
if arg.typ() == OperandType::Literal {
|
||||||
|
self.strs.push(PalString {
|
||||||
|
offset: arg.offset,
|
||||||
|
typ: StringType::Message,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
let message_func = match self.user_message_functions.get(&target_offset) {
|
let message_func = match self.user_message_functions.get(&target_offset) {
|
||||||
Some(func) => func,
|
Some(func) => func,
|
||||||
None => return Ok(()),
|
None => return Ok(()),
|
||||||
|
|||||||
Reference in New Issue
Block a user