use sbpf_assembler::ast::AST;
use sbpf_assembler::astnode::{ASTNode, ROData};
use sbpf_assembler::instruction::Instruction;
use sbpf_assembler::lexer::{ImmediateValue, Token};
use sbpf_assembler::opcode::Opcode;
use sbpf_assembler::parser::ParseResult;
use object::{File, Object, ObjectSection, ObjectSymbol};
use object::RelocationTarget::Symbol;
use anyhow::Result;
use std::collections::HashMap;
pub fn parse_bytecode(bytes: &[u8]) -> Result<ParseResult, String> {
let mut ast = AST::new();
let obj = File::parse(bytes).map_err(|e| e.to_string())?;
let ro_section = obj.section_by_name(".rodata").unwrap();
let mut rodata_table = HashMap::new();
let mut rodata_offset = 0;
for symbol in obj.symbols() {
if symbol.section_index() == Some(ro_section.index()) && symbol.size() > 0 {
let mut bytes = Vec::new();
for i in 0..symbol.size() {
bytes.push(ImmediateValue::Int(
ro_section.data().unwrap()[(symbol.address() + i) as usize] as i64));
}
ast.rodata_nodes.push(ASTNode::ROData {
rodata: ROData {
name: symbol.name().unwrap().to_string(),
args: vec![Token::Directive(String::from("byte"), 0..1) , Token::VectorLiteral(bytes.clone(), 0..1)],
span: 0..1,
},
offset: rodata_offset,
});
rodata_table.insert(symbol.address(), symbol.name().unwrap().to_string());
rodata_offset += symbol.size();
}
}
ast.set_rodata_size(rodata_offset);
for section in obj.sections() {
if section.name() == Ok(".text") {
let mut offset = 0;
while offset < section.data().unwrap().len() {
let node_len = match Opcode::from_u8(section.data().unwrap()[offset]) {
Some(Opcode::Lddw) => 16,
_ => 8,
};
let node = §ion.data().unwrap()[offset..offset + node_len];
ast.nodes.push(ASTNode::Instruction {
instruction: Instruction::from_bytes(node).unwrap(),
offset: offset as u64,
});
offset += node_len;
}
for rel in section.relocations() {
let symbol = match rel.1.target() {
Symbol(sym) => Some(obj.symbol_by_index(sym).unwrap()),
_ => None
};
if symbol.unwrap().section_index() == Some(ro_section.index()) {
let addend = match ast.get_instruction_at_offset(rel.0 as u64).unwrap()
.operands.last().unwrap().clone() {
Token::ImmediateValue(ImmediateValue::Int(val), _) => val,
_ => 0
};
let ro_label = rodata_table.get(&(addend as u64)).unwrap();
let ro_label_name = ro_label.clone();
let node: &mut Instruction = ast.get_instruction_at_offset(rel.0 as u64).unwrap();
let last_idx = node.operands.len() - 1;
node.operands[last_idx] = Token::Identifier(ro_label_name, 0..1);
}
}
ast.set_text_size(section.size());
}
}
let parse_result = ast.build_program();
if let Ok(parse_result) = parse_result {
Ok(parse_result)
} else {
Err("Failed to build program".to_string())
}
}