Przeglądaj źródła

Merge branch 'master' into feat/pest-parser

bidhan-a 1 tydzień temu
rodzic
commit
3c7df82d2e

+ 8 - 1
crates/common/src/decode.rs

@@ -284,7 +284,7 @@ pub fn decode_call_immediate(bytes: &[u8]) -> Result<Instruction, SBPFError> {
     Ok(Instruction {
         opcode,
         dst: None,
-        src: None,
+        src: Some(Register { n: src }),
         off: None,
         imm: callimm,
         span: 0..8,
@@ -294,6 +294,13 @@ pub fn decode_call_immediate(bytes: &[u8]) -> Result<Instruction, SBPFError> {
 pub fn decode_call_register(bytes: &[u8]) -> Result<Instruction, SBPFError> {
     assert!(bytes.len() >= 8);
     let (opcode, dst, src, off, imm) = parse_bytes(bytes)?;
+    // Handle SBPF Callx normalization
+    let (dst, imm) = if dst == 0 && imm != 0 {
+        (imm as u8, 0)
+    } else {
+        (dst, 0)
+    };
+
     // TODO: sbpf encodes dst_reg in immediate
     if src != 0 || off != 0 || imm != 0 {
         return Err(SBPFError::BytecodeError {

+ 37 - 0
crates/common/src/instruction.rs

@@ -85,6 +85,43 @@ impl Instruction {
         }
     }
 
+    pub fn from_bytes_sbpf_v2(bytes: &[u8]) -> Result<Self, SBPFError> {
+        // Preprocess the opcode byte for SBPF v2 (e_flags == 0x02)
+        let mut processed_bytes = bytes.to_vec();
+
+        match processed_bytes[0] {
+            // New opcodes in v2 that map to existing instructions
+            0x8C => processed_bytes[0] = 0x61, // v2: 0x8C -> ldxw dst, [src + off]
+            0x8F => processed_bytes[0] = 0x63, // v2: 0x8F -> stxw [dst + off], src
+            // Repurposed opcodes in v2
+            0x2C => processed_bytes[0] = 0x71, // v2: mul32 dst, src -> ldxb dst, [src + off]
+            0x3C => processed_bytes[0] = 0x69, // v2: div32 dst, src -> ldxh dst, [src + off]
+            0x9C => processed_bytes[0] = 0x79, // v2: mod32 dst, src -> ldxdw dst, [src + off]
+            0x27 => processed_bytes[0] = 0x72, // v2: mul64 dst, imm -> stb [dst + off], imm
+            0x2F => processed_bytes[0] = 0x73, // v2: mul64 dst, src -> stxb [dst + off], src
+            0x37 => processed_bytes[0] = 0x6A, // v2: div64 dst, imm -> sth [dst + off], imm
+            0x3F => processed_bytes[0] = 0x6B, // v2: div64 dst, src -> stxh [dst + off], src
+            0x87 => processed_bytes[0] = 0x62, // v2: neg64 dst -> stw [dst + off], imm
+            0x97 => processed_bytes[0] = 0x7A, // v2: mod64 dst, imm -> stdw [dst + off], imm
+            0x9F => processed_bytes[0] = 0x7B, // v2: mod64 dst, src -> stxdw [dst + off], src
+            // Revert Lddw
+            0x21 => {
+                if let Some(lddw_2) = processed_bytes.get(8)
+                    && lddw_2 == &0xf7
+                {
+                    processed_bytes[0] = 0x18;
+                    processed_bytes[8..12].clone_from_slice(&[0u8; 4]);
+                }
+            }
+            // Move callx target from src to dst
+            0x8D => processed_bytes[1] >>= 4,
+            // All other opcodes remain unchanged
+            _ => (),
+        }
+
+        Self::from_bytes(&processed_bytes)
+    }
+
     pub fn to_bytes(&self) -> Result<Vec<u8>, SBPFError> {
         let dst_val = self.dst.as_ref().map(|r| r.n).unwrap_or(0);
         let src_val = if self.opcode == Opcode::Call {

+ 2 - 0
crates/disassembler/src/errors.rs

@@ -18,6 +18,8 @@ pub enum DisassemblerError {
     InvalidString,
     #[error("Bytecode error: {0}")]
     BytecodeError(String),
+    #[error("Missing text section")]
+    MissingTextSection,
 }
 
 impl From<SBPFError> for DisassemblerError {

+ 49 - 2
crates/disassembler/src/program.rs

@@ -1,9 +1,13 @@
 use {
     crate::{
-        elf_header::ELFHeader, errors::DisassemblerError, program_header::ProgramHeader,
-        section_header::SectionHeader, section_header_entry::SectionHeaderEntry,
+        elf_header::{E_MACHINE_SBPF, ELFHeader},
+        errors::DisassemblerError,
+        program_header::ProgramHeader,
+        section_header::SectionHeader,
+        section_header_entry::SectionHeaderEntry,
     },
     object::{Endianness, read::elf::ElfFile64},
+    sbpf_common::{instruction::Instruction, opcode::Opcode},
     serde::{Deserialize, Serialize},
 };
 
@@ -36,6 +40,49 @@ impl Program {
             section_header_entries,
         })
     }
+
+    pub fn to_ixs(self) -> Result<Vec<Instruction>, DisassemblerError> {
+        // Find and populate instructions for the .text section
+        let text_section = self
+            .section_header_entries
+            .iter()
+            .find(|e| e.label.eq(".text\0"))
+            .ok_or(DisassemblerError::MissingTextSection)?;
+        let data = &text_section.data;
+        if !data.len().is_multiple_of(8) {
+            return Err(DisassemblerError::InvalidDataLength);
+        }
+        let mut ixs: Vec<Instruction> = vec![];
+        let mut pos = 0;
+
+        let is_sbpf_v2 =
+            self.elf_header.e_flags == 0x02 && self.elf_header.e_machine == E_MACHINE_SBPF;
+        // Handle pre-processing
+
+        while pos < data.len() {
+            let remaining = &data[pos..];
+            if remaining.len() < 8 {
+                break;
+            }
+
+            // ugly v2 shit we need to fix goes here:
+            let ix = if is_sbpf_v2 {
+                Instruction::from_bytes_sbpf_v2(remaining)?
+            } else {
+                Instruction::from_bytes(remaining)?
+            };
+
+            if ix.opcode == Opcode::Lddw {
+                pos += 16;
+            } else {
+                pos += 8;
+            }
+
+            ixs.push(ix);
+        }
+
+        Ok(ixs)
+    }
 }
 
 #[cfg(test)]

+ 21 - 18
crates/disassembler/src/section_header.rs

@@ -9,24 +9,25 @@ use {
 #[derive(Debug, Clone, Serialize, Deserialize)]
 #[repr(u32)]
 pub enum SectionHeaderType {
-    SHT_NULL = 0x00,          // Section header table entry unused
-    SHT_PROGBITS = 0x01,      // Program data
-    SHT_SYMTAB = 0x02,        // Symbol table
-    SHT_STRTAB = 0x03,        // String table
-    SHT_RELA = 0x04,          // Relocation entries with addends
-    SHT_HASH = 0x05,          // Symbol hash table
-    SHT_DYNAMIC = 0x06,       // Dynamic linking information
-    SHT_NOTE = 0x07,          // Notes
-    SHT_NOBITS = 0x08,        // Program space with no data (bss)
-    SHT_REL = 0x09,           // Relocation entries, no addends
-    SHT_SHLIB = 0x0A,         // Reserved
-    SHT_DYNSYM = 0x0B,        // Dynamic linker symbol table
-    SHT_INIT_ARRAY = 0x0E,    // Array of constructors
-    SHT_FINI_ARRAY = 0x0F,    // Array of destructors
-    SHT_PREINIT_ARRAY = 0x10, // Array of pre-constructors
-    SHT_GROUP = 0x11,         // Section group
-    SHT_SYMTAB_SHNDX = 0x12,  // Extended section indices
-    SHT_NUM = 0x13,           // Number of defined types.
+    SHT_NULL = 0x00,           // Section header table entry unused
+    SHT_PROGBITS = 0x01,       // Program data
+    SHT_SYMTAB = 0x02,         // Symbol table
+    SHT_STRTAB = 0x03,         // String table
+    SHT_RELA = 0x04,           // Relocation entries with addends
+    SHT_HASH = 0x05,           // Symbol hash table
+    SHT_DYNAMIC = 0x06,        // Dynamic linking information
+    SHT_NOTE = 0x07,           // Notes
+    SHT_NOBITS = 0x08,         // Program space with no data (bss)
+    SHT_REL = 0x09,            // Relocation entries, no addends
+    SHT_SHLIB = 0x0A,          // Reserved
+    SHT_DYNSYM = 0x0B,         // Dynamic linker symbol table
+    SHT_INIT_ARRAY = 0x0E,     // Array of constructors
+    SHT_FINI_ARRAY = 0x0F,     // Array of destructors
+    SHT_PREINIT_ARRAY = 0x10,  // Array of pre-constructors
+    SHT_GROUP = 0x11,          // Section group
+    SHT_SYMTAB_SHNDX = 0x12,   // Extended section indices
+    SHT_NUM = 0x13,            // Number of defined types.
+    SHT_GNU_HASH = 0x6ffffff6, // GNU Hash
 }
 
 impl TryFrom<u32> for SectionHeaderType {
@@ -52,6 +53,7 @@ impl TryFrom<u32> for SectionHeaderType {
             0x11 => Self::SHT_GROUP,
             0x12 => Self::SHT_SYMTAB_SHNDX,
             0x13 => Self::SHT_NUM,
+            0x6ffffff6 => Self::SHT_GNU_HASH,
             _ => return Err(DisassemblerError::InvalidSectionHeaderType),
         })
     }
@@ -84,6 +86,7 @@ impl From<SectionHeaderType> for &str {
             SectionHeaderType::SHT_GROUP => "SHT_GROUP",
             SectionHeaderType::SHT_SYMTAB_SHNDX => "SHT_SYMTAB_SHNDX",
             SectionHeaderType::SHT_NUM => "SHT_NUM",
+            SectionHeaderType::SHT_GNU_HASH => "SHT_GNU_HASH",
         }
     }
 }

+ 11 - 44
crates/disassembler/src/section_header_entry.rs

@@ -1,6 +1,6 @@
 use {
     crate::errors::DisassemblerError,
-    sbpf_common::{instruction::Instruction, opcode::Opcode},
+    sbpf_common::instruction::Instruction,
     serde::{Deserialize, Serialize},
     std::fmt::Debug,
 };
@@ -26,10 +26,6 @@ impl SectionHeaderEntry {
             utf8: String::new(),
         };
 
-        if h.label.contains(".text\0") {
-            h.ixs = h.to_ixs()?;
-        }
-
         if let Ok(utf8) = String::from_utf8(h.data.clone()) {
             h.utf8 = utf8;
         }
@@ -40,32 +36,6 @@ impl SectionHeaderEntry {
         self.offset
     }
 
-    pub fn to_ixs(&self) -> Result<Vec<Instruction>, DisassemblerError> {
-        if !self.data.len().is_multiple_of(8) {
-            return Err(DisassemblerError::InvalidDataLength);
-        }
-        let mut ixs: Vec<Instruction> = vec![];
-        let mut pos = 0;
-
-        while pos < self.data.len() {
-            let remaining = &self.data[pos..];
-            if remaining.len() < 8 {
-                break;
-            }
-
-            let ix = Instruction::from_bytes(remaining)?;
-            if ix.opcode == Opcode::Lddw {
-                pos += 16;
-            } else {
-                pos += 8;
-            }
-
-            ixs.push(ix);
-        }
-
-        Ok(ixs)
-    }
-
     pub fn to_bytes(&self) -> Vec<u8> {
         self.data.clone()
     }
@@ -92,7 +62,7 @@ mod test {
 
         let h = SectionHeaderEntry::new(".text\0".to_string(), 128, data.clone()).unwrap();
 
-        let ixs = vec![
+        let ixs = [
             Instruction {
                 opcode: Opcode::Lddw,
                 dst: Some(Register { n: 1 }),
@@ -100,7 +70,9 @@ mod test {
                 off: None,
                 imm: Some(Either::Right(Number::Int(0))),
                 span: 0..16,
-            },
+            }
+            .to_bytes()
+            .unwrap(),
             Instruction {
                 opcode: Opcode::Exit,
                 dst: None,
@@ -108,17 +80,12 @@ mod test {
                 off: None,
                 imm: None,
                 span: 0..8,
-            },
-        ];
-        assert_eq!(ixs, h.to_ixs().unwrap());
+            }
+            .to_bytes()
+            .unwrap(),
+        ]
+        .concat();
 
-        assert_eq!(
-            data,
-            h.to_ixs()
-                .expect("Invalid IX")
-                .into_iter()
-                .flat_map(|i| i.to_bytes().unwrap())
-                .collect::<Vec<u8>>()
-        )
+        assert_eq!(ixs, h.to_bytes());
     }
 }