mirror of
https://github.com/Zenithsiz/dcb.git
synced 2026-02-13 05:13:10 +00:00
Directive now only decodes dw after the code end.
Load/Store instructions now display what function/string/data they're loading inline.
This commit is contained in:
@@ -250,69 +250,56 @@ fn main() -> Result<(), anyhow::Error> {
|
||||
) |
|
||||
Instruction::Pseudo(
|
||||
PseudoInstruction::B { target } | PseudoInstruction::Beqz { target, .. } | PseudoInstruction::Bnez { target, .. },
|
||||
) => {
|
||||
if let Some((target, prefix)) = functions
|
||||
.get(*target)
|
||||
.map(|func| (&func.name, ""))
|
||||
.or_else(|| cur_func.and_then(|func| func.labels.get(target).map(|label| (label, "."))))
|
||||
{
|
||||
// TODO: Improve solution, removing the target like this isn't
|
||||
// a good way of going about it.
|
||||
let instruction = instruction.to_string();
|
||||
#[allow(clippy::indexing_slicing)] // This can't panic, it's index is `..{0..len}`.
|
||||
let instruction = &instruction[..instruction.rfind(' ').unwrap_or_else(|| instruction.len())];
|
||||
print!("{instruction} {prefix}{target}");
|
||||
} else {
|
||||
print!("{instruction}");
|
||||
}
|
||||
) => match functions
|
||||
.get(*target)
|
||||
.map(|func| (&func.name, ""))
|
||||
.or_else(|| cur_func.and_then(|func| func.labels.get(target).map(|label| (label, "."))))
|
||||
{
|
||||
Some((target, prefix)) => print!("{} {prefix}{target}", strip_last_arg(instruction)),
|
||||
None => print!("{instruction}"),
|
||||
},
|
||||
_ => print!("{instruction}"),
|
||||
}
|
||||
|
||||
// Check if we should have any comments with this instruction
|
||||
|
||||
match instruction {
|
||||
// Comment loading address, loading and writing values of string and data
|
||||
// TODO: Maybe check loads / writes to halfway between
|
||||
// the strings / data.
|
||||
Instruction::Pseudo(
|
||||
PseudoInstruction::La { target: offset, .. } |
|
||||
PseudoInstruction::Li32 { imm: offset, .. } |
|
||||
PseudoInstruction::LbImm { offset, .. } |
|
||||
PseudoInstruction::LbuImm { offset, .. } |
|
||||
PseudoInstruction::LhImm { offset, .. } |
|
||||
PseudoInstruction::LhuImm { offset, .. } |
|
||||
PseudoInstruction::LwlImm { offset, .. } |
|
||||
PseudoInstruction::LwImm { offset, .. } |
|
||||
PseudoInstruction::LwrImm { offset, .. } |
|
||||
PseudoInstruction::SbImm { offset, .. } |
|
||||
PseudoInstruction::ShImm { offset, .. } |
|
||||
PseudoInstruction::SwlImm { offset, .. } |
|
||||
PseudoInstruction::SwImm { offset, .. } |
|
||||
PseudoInstruction::SwrImm { offset, .. },
|
||||
) => {
|
||||
if let Some(string_idx) = strings_pos.get(Pos::ref_cast(offset)) {
|
||||
print!(" # string_{string_idx}");
|
||||
}
|
||||
if let Some(data_idx) = data_pos.get(Pos::ref_cast(offset)) {
|
||||
print!(" # data_{data_idx}");
|
||||
}
|
||||
PseudoInstruction::La { target, .. } |
|
||||
PseudoInstruction::Li32 { imm: target, .. } |
|
||||
PseudoInstruction::LbImm { offset: target, .. } |
|
||||
PseudoInstruction::LbuImm { offset: target, .. } |
|
||||
PseudoInstruction::LhImm { offset: target, .. } |
|
||||
PseudoInstruction::LhuImm { offset: target, .. } |
|
||||
PseudoInstruction::LwlImm { offset: target, .. } |
|
||||
PseudoInstruction::LwImm { offset: target, .. } |
|
||||
PseudoInstruction::LwrImm { offset: target, .. } |
|
||||
PseudoInstruction::SbImm { offset: target, .. } |
|
||||
PseudoInstruction::ShImm { offset: target, .. } |
|
||||
PseudoInstruction::SwlImm { offset: target, .. } |
|
||||
PseudoInstruction::SwImm { offset: target, .. } |
|
||||
PseudoInstruction::SwrImm { offset: target, .. },
|
||||
) => match strings_pos
|
||||
.get(Pos::ref_cast(target))
|
||||
.map(|idx| (idx, "string_"))
|
||||
.or_else(|| data_pos.get(Pos::ref_cast(target)).map(|idx| (idx, "data_")))
|
||||
{
|
||||
Some((target, prefix)) => print!("{} {prefix}{target}", strip_last_arg(instruction)),
|
||||
None => print!("{instruction}"),
|
||||
},
|
||||
|
||||
// Comment `dw`s with both function and data
|
||||
Instruction::Directive(Directive::Dw(offset) | Directive::DwRepeated { value: offset, .. }) => {
|
||||
if let Some(func) = functions.get(Pos(*offset)) {
|
||||
print!(" # {}", func.name);
|
||||
}
|
||||
if let Some(string_idx) = strings_pos.get(Pos::ref_cast(offset)) {
|
||||
print!(" # string_{string_idx}");
|
||||
}
|
||||
if let Some(data_idx) = data_pos.get(Pos::ref_cast(offset)) {
|
||||
print!(" # data_{data_idx}");
|
||||
}
|
||||
},
|
||||
_ => print!("{instruction}"),
|
||||
}
|
||||
|
||||
_ => (),
|
||||
// Comment any `dw` instructions that are function, data or string pointers
|
||||
if let Instruction::Directive(Directive::Dw(target) | Directive::DwRepeated { value: target, .. }) = instruction {
|
||||
if let Some(func) = functions.get(Pos(*target)) {
|
||||
print!(" # {}", func.name);
|
||||
}
|
||||
if let Some(string_idx) = strings_pos.get(Pos::ref_cast(target)) {
|
||||
print!(" # string_{string_idx}");
|
||||
}
|
||||
if let Some(data_idx) = data_pos.get(Pos::ref_cast(target)) {
|
||||
print!(" # data_{data_idx}");
|
||||
}
|
||||
}
|
||||
|
||||
// Append any comments in this line
|
||||
@@ -336,3 +323,13 @@ fn main() -> Result<(), anyhow::Error> {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
/// Helper function to extract the last argument from an instruction
|
||||
// TODO: Use something better than this
|
||||
fn strip_last_arg(instruction: &Instruction) -> String {
|
||||
let mut instruction: String = instruction.to_string();
|
||||
// Note: This can't panic
|
||||
instruction.truncate(instruction.rfind(' ').unwrap_or(0));
|
||||
instruction
|
||||
}
|
||||
|
||||
@@ -94,7 +94,7 @@ impl Func<&'static str> {
|
||||
Pos(0x80056280) => "zero_loop",
|
||||
},
|
||||
start_pos: Pos(0x80056270),
|
||||
end_pos: Pos(0x80056384),
|
||||
end_pos: Pos(0x80056388),
|
||||
},
|
||||
])
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//! Directives
|
||||
|
||||
// Imports
|
||||
use super::{FromRawIter, Raw};
|
||||
use super::{FromRawIter, Instruction, Raw};
|
||||
use crate::game::exe::Pos;
|
||||
use ascii::{AsciiChar, AsciiStr, AsciiString};
|
||||
use AsciiChar::Null;
|
||||
@@ -29,6 +29,41 @@ pub enum Directive {
|
||||
Ascii(AsciiString),
|
||||
}
|
||||
|
||||
impl Directive {
|
||||
/// Decodes a `dw` instruction
|
||||
pub fn decode_dw(first_raw: Raw, iter: &mut (impl Iterator<Item = Raw> + Clone)) -> Self {
|
||||
let mut times_repeated = 0;
|
||||
|
||||
// Keep getting values until either eof or a different one
|
||||
loop {
|
||||
let mut cur_iter = iter.clone();
|
||||
match cur_iter.next().map(|next_raw| next_raw.repr == first_raw.repr) {
|
||||
// If we got a different value, keep fetching values until they're different
|
||||
Some(true) => {
|
||||
*iter = cur_iter;
|
||||
times_repeated += 1;
|
||||
},
|
||||
|
||||
// If we didn't get it or we got a different value, exit
|
||||
// Note: No need t update the iterator, as it either returned `None` or
|
||||
// a different raw.
|
||||
None | Some(false) => match times_repeated {
|
||||
// If the value didn't repeat, use a single `dw`
|
||||
0 => break Self::Dw(first_raw.repr),
|
||||
|
||||
// Else return the table
|
||||
_ => {
|
||||
break Self::DwRepeated {
|
||||
value: first_raw.repr,
|
||||
len: times_repeated + 1,
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Helper function to check if a string has null and if everything after the first
|
||||
/// null is also null (or if there were no nulls).
|
||||
@@ -52,6 +87,12 @@ impl FromRawIter for Directive {
|
||||
// Get the first raw
|
||||
let raw = iter.next()?;
|
||||
|
||||
// If we're past all the code, there are no more strings,
|
||||
// so just decode a `dw`.
|
||||
if raw.pos >= Instruction::CODE_END {
|
||||
return Some((raw.pos, Self::decode_dw(raw, iter)));
|
||||
}
|
||||
|
||||
// Try to get an ascii string from the raw and check for nulls
|
||||
match AsciiString::from_ascii(raw.repr.to_ne_bytes()).map(check_nulls) {
|
||||
// If we got a string with at least 1 non-null, but
|
||||
@@ -101,37 +142,7 @@ impl FromRawIter for Directive {
|
||||
|
||||
// Else if it was full null, non-uniformly null or non-ascii,
|
||||
// try to get a dw table
|
||||
_ => {
|
||||
let mut times_repeated = 0;
|
||||
|
||||
// Keep getting values until either eof or a different one
|
||||
loop {
|
||||
let mut cur_iter = iter.clone();
|
||||
match cur_iter.next().map(|next_raw| next_raw.repr == raw.repr) {
|
||||
// If we got a different value, keep fetching values until they're different
|
||||
Some(true) => {
|
||||
*iter = cur_iter;
|
||||
times_repeated += 1;
|
||||
},
|
||||
|
||||
// If we didn't get it or we got a different value, exit
|
||||
// Note: No need t update the iterator, as it either returned `None` or
|
||||
// a different raw.
|
||||
None | Some(false) => match times_repeated {
|
||||
// If the value didn't repeat, use a single `dw`
|
||||
0 => break Some((raw.pos, Self::Dw(raw.repr))),
|
||||
|
||||
// Else return the table
|
||||
_ => {
|
||||
break Some((raw.pos, Self::DwRepeated {
|
||||
value: raw.repr,
|
||||
len: times_repeated + 1,
|
||||
}))
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => Some((raw.pos, Self::decode_dw(raw, iter))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user