Merge with new objdump code
This commit is contained in:
commit
6cfdc7ffaf
|
@ -82,7 +82,7 @@
|
||||||
"",
|
"",
|
||||||
"--help",
|
"--help",
|
||||||
"--list -o ../Tests/Test_Planschbecken psx bin-cue ../Tests/ISO_Planschbecken.xml",
|
"--list -o ../Tests/Test_Planschbecken psx bin-cue ../Tests/ISO_Planschbecken.xml",
|
||||||
"${workspaceFolder}/../../examples/PoolBox/application/bin/PSX-release/PoolBox.map"
|
"--wsl ../../../examples/PoolBox/application/bin/PSX-release/PoolBox.elf"
|
||||||
],
|
],
|
||||||
"default": "",
|
"default": "",
|
||||||
"description": "Argument options to pass to cargo run"
|
"description": "Argument options to pass to cargo run"
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
use super::Error;
|
||||||
|
use super::types::{MemoryMap, Symbol};
|
||||||
|
use tool_helper::Output;
|
||||||
|
|
||||||
|
pub fn write(mut out: Output, memory_map: &MemoryMap) -> Result<Output, Error> {
|
||||||
|
const NAME_WIDTH:usize = 64;
|
||||||
|
fn print_symbols(out: &mut Output, symbols: &Vec<Symbol>) -> Result<(), Error> {
|
||||||
|
for symbol in symbols {
|
||||||
|
let mut name = symbol.name.as_str();
|
||||||
|
|
||||||
|
if name.len() > NAME_WIDTH {
|
||||||
|
writeln!(out, "\t{}", name)?;
|
||||||
|
name = " ";
|
||||||
|
}
|
||||||
|
|
||||||
|
writeln!(out, "\t{:<width$} @0x{:X}", name, symbol.adr, width=NAME_WIDTH)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
writeln!(out, "<GLOBAL>:")?;
|
||||||
|
print_symbols(&mut out, &memory_map.global)?;
|
||||||
|
for section in &memory_map.sections {
|
||||||
|
let section_end = section.adr + section.size as u64;
|
||||||
|
|
||||||
|
writeln!(out, "{}: @0x{:X} - 0x{:X}", section.name, section.adr, section_end)?;
|
||||||
|
print_symbols(&mut out, §ion.symbols)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(out)
|
||||||
|
}
|
|
@ -1,202 +1,131 @@
|
||||||
pub mod types;
|
pub mod types;
|
||||||
|
pub mod dump;
|
||||||
|
|
||||||
use tool_helper::{Error, Input};
|
use tool_helper::Error;
|
||||||
use std::io::BufRead;
|
use types::{MemoryMap, Section, Symbol};
|
||||||
use types::{Content, MemoryMapInfo, Section};
|
|
||||||
|
|
||||||
pub fn scan(input: Input) -> Result<MemoryMapInfo, Error> {
|
pub fn scan<F: FnMut() -> Option<String>>(mut next_line: F) -> Result<MemoryMap, Error> {
|
||||||
let (sections, highest_address) = process(input.lines().map(|l| l.unwrap()).into_iter())?;
|
const SECTION_IDENTIFIER:&'static str = "Sections:";
|
||||||
|
const SYMBOL_TABLE_IDENTIFIER:&'static str = "SYMBOL TABLE:";
|
||||||
|
|
||||||
Ok(MemoryMapInfo{sections, highest_address: highest_address})
|
let mut memory_map = MemoryMap::default();
|
||||||
}
|
|
||||||
|
|
||||||
fn process<F: std::iter::Iterator<Item=String>>(mut line_iter:F) -> Result<(Vec<Section>, u64), Error> {
|
while let Some(mut line) = next_line() {
|
||||||
let mut sections = Vec::new();
|
|
||||||
let mut highest_address = 0u64;
|
|
||||||
|
|
||||||
while let Some(mut line) = line_iter.next() {
|
|
||||||
loop {
|
loop {
|
||||||
if line.starts_with(".") {
|
// loop so we pick-up changes of line
|
||||||
let (new_line, new_section) = process_section(&mut highest_address, line, &mut line_iter)?;
|
if line == SECTION_IDENTIFIER {
|
||||||
|
line = scan_sections(&mut next_line, &mut memory_map.sections)?;
|
||||||
sections.push(new_section);
|
continue;
|
||||||
line = new_line;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
else {
|
if line == SYMBOL_TABLE_IDENTIFIER {
|
||||||
break;
|
// Process Symbol table here
|
||||||
|
line = scan_symbols(&mut next_line, &mut memory_map)?;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sort_memory_map(&mut memory_map);
|
||||||
|
Ok(memory_map)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sort_memory_map(memory_map: &mut MemoryMap) {
|
||||||
|
fn sort_symbol_vec(symbol_vec: &mut Vec<Symbol>) {
|
||||||
|
symbol_vec.sort_by(|a, b| {
|
||||||
|
a.adr.cmp(&b.adr)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sort_section_vec(section_vec: &mut Vec<Section>) {
|
||||||
|
section_vec.sort_by(|a, b| {
|
||||||
|
a.adr.cmp(&b.adr)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
sort_section_vec(&mut memory_map.sections);
|
||||||
|
sort_symbol_vec(&mut memory_map.global);
|
||||||
|
for section in &mut memory_map.sections {
|
||||||
|
sort_symbol_vec(&mut section.symbols);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn scan_symbols<F: FnMut() -> Option<String>>(next_line: &mut F, memory_map: &mut MemoryMap) -> Result<String, Error> {
|
||||||
|
fn find_section<'a>(name: &str, memory_map: &'a mut MemoryMap) -> Option<&'a mut Section> {
|
||||||
|
for section in &mut memory_map.sections {
|
||||||
|
if section.name == name {
|
||||||
|
return Some(section);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
sections.sort_by(|left, right| {
|
fn skip_symbol(name: &str, section_name: &str) -> bool {
|
||||||
left.adr.cmp(&right.adr)
|
name == section_name || name.ends_with(".cpp") || name.ends_with(".c") || name.ends_with(".cxx")
|
||||||
});
|
|
||||||
Ok((sections, highest_address))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn process_section<F: std::iter::Iterator<Item=String>>(highest_address: &mut u64, line: String, line_iter:&mut F) -> Result<(String, Section), Error> {
|
|
||||||
let mut next_line_closure = || {
|
|
||||||
line_iter.next().ok_or(Error::from_str("Unexpected end of file"))
|
|
||||||
};
|
|
||||||
let (mut section, line) = read_section(line, &mut next_line_closure)?;
|
|
||||||
|
|
||||||
Ok((process_subsection(&mut section, highest_address, line, &mut next_line_closure)?, section))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn process_subsection<F:FnMut()-> Result<String, Error>>(section: &mut Section, highest_address: &mut u64, line: Option<String>, next_line: &mut F) -> Result<String, Error> {
|
|
||||||
fn push_sub_section(section: &mut Section, sub_section: Option<Section>) {
|
|
||||||
if let Some(sub_section) = sub_section {
|
|
||||||
section.content.push(Content::Section(sub_section));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn add_element<T>(sub_section: Option<Section>, section: &mut Section, value: T, callback: fn(&mut Section, T)) -> Option<Section> {
|
|
||||||
if let Some(mut sub_section) = sub_section {
|
|
||||||
callback(&mut sub_section, value);
|
|
||||||
Some(sub_section)
|
|
||||||
}
|
|
||||||
|
|
||||||
else {
|
|
||||||
callback(section, value);
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut line = {
|
while let Some(line) = next_line() {
|
||||||
if let Some(line) = line {
|
if line.chars().all(char::is_whitespace) {
|
||||||
line
|
|
||||||
}
|
|
||||||
|
|
||||||
else {
|
|
||||||
next_line()?
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut next_line_closure = || -> Result<String, Error> {
|
|
||||||
if let Ok(line) = next_line() {
|
|
||||||
return Ok(line);
|
return Ok(line);
|
||||||
}
|
}
|
||||||
|
|
||||||
else {
|
let split_count = line.split_whitespace().count();
|
||||||
// EOF
|
let mut split_line = line.split_whitespace();
|
||||||
return Ok(String::from(""));
|
let adr = split_line_radix(&mut split_line, 16, "Address of Symbol")?;
|
||||||
|
let _type = split_line.next().ok_or(Error::from_str("Failed obtaining type of symbol"))?;
|
||||||
|
if split_count > 5 {
|
||||||
|
let _flag = split_line.next().ok_or(Error::from_str("Failed obtaining flag of symbol"))?;
|
||||||
}
|
}
|
||||||
};
|
let section = split_line.next().ok_or(Error::from_str("Failed obtaining section of symbol"))?;
|
||||||
|
let size = split_line_radix(&mut split_line, 16, "Size of Symbol")? as usize;
|
||||||
|
let name = split_line.next().ok_or(Error::from_str("Failed obtaining name of symbol"))?;
|
||||||
|
|
||||||
let mut sub_section = None;
|
if skip_symbol(name, section) {
|
||||||
|
// Not of interest
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
loop {
|
let symbol = Symbol::new(name.to_string(), adr, size);
|
||||||
if line.starts_with(" .") {
|
if let Some(section) = find_section(section, memory_map) {
|
||||||
push_sub_section(section, sub_section);
|
if section.contains_adr(adr) {
|
||||||
let (section, new_line) = read_section(line, &mut next_line_closure)?;
|
section.symbols.push(symbol);
|
||||||
|
// Do not add to global cause they have a section
|
||||||
sub_section = Some(section);
|
|
||||||
|
|
||||||
if let Some(new_line) = new_line {
|
|
||||||
line = new_line;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else if line.starts_with(" *fill*") {
|
memory_map.global.push(symbol);
|
||||||
let fill = read_fill(line)?;
|
|
||||||
sub_section = add_element(sub_section, section, fill, |section, fill| {
|
|
||||||
section.content.push(Content::Fill(fill));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
else if line.starts_with(" 0x") {
|
|
||||||
if let Some(symbol) = parse_symbol(read_symbol(line)?) {
|
|
||||||
if symbol.adr > *highest_address {
|
|
||||||
*highest_address = symbol.adr;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub_section = add_element(sub_section, section, symbol, |section, symbol| {
|
|
||||||
section.content.push(Content::Symbol(symbol));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
else if line.is_empty() {
|
|
||||||
push_sub_section(section, sub_section);
|
|
||||||
return Ok(line);
|
|
||||||
}
|
|
||||||
|
|
||||||
line = next_line_closure()?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Err(Error::from_str("Failed obtaining all Symbols"))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_section<F:FnMut()-> Result<String, Error>>(mut line: String, next_line: &mut F) -> Result<(Section, Option<String>), Error> {
|
fn scan_sections<F: FnMut() -> Option<String>>(next_line: &mut F, sections: &mut Vec<Section>) -> Result<String, Error> {
|
||||||
let mut split_line = line.split_whitespace();
|
while let Some(_) = next_line() {
|
||||||
let name = split_line.next().ok_or(Error::from_str("Couldn't locate section name"))?.to_string();
|
// We read every other line
|
||||||
let need_new_line = name.chars().count() > 16;
|
let line = next_line().ok_or(Error::from_str("Failed skipping to next section"))?;
|
||||||
|
let mut split_line = line.split_whitespace();
|
||||||
|
if let Ok(_) = split_line_radix(&mut split_line, 10, "") {
|
||||||
|
let name = split_line.next().ok_or(Error::from_str("Failed reading Section Name"))?;
|
||||||
|
let size = split_line_radix(&mut split_line, 16, "Section Size")?;
|
||||||
|
let adr = split_line_radix(&mut split_line, 16, "Section Address")?;
|
||||||
|
|
||||||
if need_new_line {
|
sections.push(Section::new(name.to_string(), adr, size as usize));
|
||||||
line = next_line()?;
|
|
||||||
split_line = line.split_whitespace();
|
|
||||||
}
|
|
||||||
|
|
||||||
let adr = read_as::<u64>(split_line.next());
|
|
||||||
if adr.is_none() {
|
|
||||||
return Ok((Section::new(name, None, None, None), {
|
|
||||||
if need_new_line {
|
|
||||||
Some(line)
|
|
||||||
}
|
|
||||||
|
|
||||||
else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
let size = read_as::<usize>(split_line.next());
|
|
||||||
let file = {
|
|
||||||
if let Some(file) = split_line.next() {
|
|
||||||
Some(file.to_string())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
else {
|
else {
|
||||||
None
|
return Ok(line);
|
||||||
}
|
}
|
||||||
};
|
|
||||||
Ok((Section::new(name, adr, size, file), None))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read_fill(line: String) -> Result<types::Fill, Error> {
|
|
||||||
let mut split_line = line.split_whitespace().skip(1);
|
|
||||||
let adr = read_as::<u64>(split_line.next()).ok_or_else(|| {return Error::from_str("*fill* statement requires an address")})?;
|
|
||||||
let size = read_as::<usize>(split_line.next()).ok_or_else(|| {return Error::from_str("*fill* statement requires a size")})?;
|
|
||||||
|
|
||||||
Ok(types::Fill::new(adr, size))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read_symbol(line: String) -> Result<types::Symbol, Error> {
|
|
||||||
let mut split_line = line.split_whitespace();
|
|
||||||
let adr = read_as::<u64>(split_line.next()).ok_or_else(|| {return Error::from_str("Symbol statement requires an address")})?;
|
|
||||||
let mut name = split_line.next().ok_or_else(|| {return Error::from_str("Symbol statement requires a symbol name")})?.to_string();
|
|
||||||
|
|
||||||
for fragment in split_line {
|
|
||||||
name += fragment;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(types::Symbol::new(name, adr))
|
Err(Error::from_str("Failed obtaining complete section"))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_symbol(mut symbol: types::Symbol) -> Option<types::Symbol> {
|
fn split_line_radix<'a>(split_line: &mut std::str::SplitWhitespace<'a>, radix: u32, value_name: &str) -> Result<u64, Error> {
|
||||||
if symbol.name.starts_with(".") {
|
match u64::from_str_radix(split_line.next().ok_or(Error::from_text(format!("Failed reading: {}", value_name)))?, radix) {
|
||||||
return None;
|
Ok(value) => Ok(value),
|
||||||
}
|
Err(error) => Err(Error::from_text(format!("Converting value for {} failed with: {}", value_name, error)))
|
||||||
|
|
||||||
symbol.name = symbol.name.split('=').next().unwrap().to_owned();
|
|
||||||
Some(symbol)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read_as<F: num_traits::Num>(str: Option<&str>) -> Option<F> {
|
|
||||||
if let Some(str) = str {
|
|
||||||
F::from_str_radix(str.trim_start_matches("0x"), 16).ok()
|
|
||||||
}
|
|
||||||
|
|
||||||
else {
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,68 @@
|
||||||
|
use clap::Parser;
|
||||||
|
use tool_helper::{Error, exit_with_error};
|
||||||
|
use readmap::types::MemoryMap;
|
||||||
|
use std::{io::{BufRead, BufReader}, path::PathBuf, process::{Child, Command, Stdio}};
|
||||||
|
|
||||||
|
#[derive(Parser)]
|
||||||
|
#[clap(about = "Opens and scans a MAP file to print extended information", long_about = None)]
|
||||||
|
struct CommandLine {
|
||||||
|
#[clap(value_parser, help="Input MAP file for scannning")]
|
||||||
|
input: PathBuf,
|
||||||
|
#[clap(long="wsl", default_value_t=false)]
|
||||||
|
use_wsl: bool,
|
||||||
|
#[clap(short='o')]
|
||||||
|
output: Option<PathBuf>
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn main() {
|
||||||
|
match CommandLine::try_parse() {
|
||||||
|
Ok(cmd_line) => {
|
||||||
|
match run_main(cmd_line) {
|
||||||
|
Ok(_) => (),
|
||||||
|
Err(error) => exit_with_error(error)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Err(error) => {
|
||||||
|
println!("{}", error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run_objdump(use_wsl: bool, input: PathBuf) -> Result<Child, Error> {
|
||||||
|
let command_list = ["wsl", "objdump", "-x"];
|
||||||
|
let start_idx = {
|
||||||
|
if use_wsl {0}
|
||||||
|
else {1}
|
||||||
|
};
|
||||||
|
let mut process = Command::new(command_list[start_idx]);
|
||||||
|
|
||||||
|
for arg in command_list.iter().skip(start_idx + 1) {
|
||||||
|
process.arg(arg);
|
||||||
|
}
|
||||||
|
process.arg(input.to_str().ok_or_else(||{Error::from_str("Failed converting input string")})?);
|
||||||
|
|
||||||
|
Ok(process.stdout(Stdio::piped()).spawn()?)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run_main(cmd: CommandLine) -> Result<(), Error> {
|
||||||
|
let output = tool_helper::open_output(cmd.output)?;
|
||||||
|
let memory_map = generate_memory_map(cmd.use_wsl, cmd.input)?;
|
||||||
|
|
||||||
|
readmap::dump::write(output, &memory_map)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_memory_map(use_wsl: bool, input: PathBuf) -> Result<MemoryMap, Error> {
|
||||||
|
let mut child = run_objdump(use_wsl, input)?;
|
||||||
|
if let Some(stdout) = &mut child.stdout {
|
||||||
|
let mut line_iter = BufReader::new(stdout).lines().map(|l| l.unwrap()).into_iter();
|
||||||
|
|
||||||
|
readmap::scan(|| {
|
||||||
|
line_iter.next()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
Err(Error::from_str("Failed opening \"stdout\" for objdump"))
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,47 +5,39 @@ pub struct MemoryMapInfo {
|
||||||
pub highest_address: u64,
|
pub highest_address: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct MemoryMap {
|
||||||
|
pub global: Vec<Symbol>,
|
||||||
|
pub sections: Vec<Section>
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct Section {
|
pub struct Section {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub adr: Option<u64>,
|
pub adr: u64,
|
||||||
pub size: Option<usize>,
|
pub size: usize,
|
||||||
pub file: Option<String>,
|
pub symbols: Vec<Symbol>
|
||||||
pub content: Vec<Content>
|
}
|
||||||
|
|
||||||
|
impl Section {
|
||||||
|
pub fn new(name: String, adr: u64, size: usize) -> Section {
|
||||||
|
Section{name, adr, size, symbols: Vec::new()}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn contains_adr(&self, adr: u64) -> bool {
|
||||||
|
adr >= self.adr && adr < (self.adr + self.size as u64)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct Symbol {
|
pub struct Symbol {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub adr: u64,
|
pub adr: u64,
|
||||||
}
|
pub size: usize
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
pub struct Fill {
|
|
||||||
pub adr: u64,
|
|
||||||
pub size: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum Content {
|
|
||||||
Fill(Fill),
|
|
||||||
Section(Section),
|
|
||||||
Symbol(Symbol),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Section {
|
|
||||||
pub fn new(name: String, adr: Option<u64>, size: Option<usize>, file: Option<String>) -> Section {
|
|
||||||
Section{name, adr, size, file, content: Vec::new()}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Symbol {
|
impl Symbol {
|
||||||
pub fn new(name: String, adr: u64) -> Symbol {
|
pub fn new(name: String, adr: u64, size: usize) -> Symbol {
|
||||||
Symbol{name, adr}
|
Symbol{name, adr, size}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Fill {
|
|
||||||
pub fn new(adr: u64, size: usize) -> Fill {
|
|
||||||
Fill{adr, size}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue