Skip to content

Commit b383e61

Browse files
authored
Refactor Error (#234)
* Distinguish aot errors * Add more message for ElfParseError * Add ElfSegmentUnreadable and ElfSegmentWritableAndExecutable error * Rename InvalidCycles to CyclesExceeded * Rename InvalidElfBits to ElfBits * Rename Unaligned to MemPageUnalignedAccess * Sorted enum * Distinguish InvalidPermission to MemWriteOnExecutablePage and MemWriteOnFreezedPage * Distinguish OutOfBound error * Flow xxuejie's review suggestions * Refactor Unexpected => Unexpected(String)
1 parent 5d417a1 commit b383e61

File tree

18 files changed

+217
-179
lines changed

18 files changed

+217
-179
lines changed

src/decoder.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ impl Decoder {
8888
pub fn decode_raw<M: Memory>(&mut self, memory: &mut M, pc: u64) -> Result<Instruction, Error> {
8989
// since we are using RISCV_MAX_MEMORY as the default key in the instruction cache, have to check out of bound error first
9090
if pc as usize >= RISCV_MAX_MEMORY {
91-
return Err(Error::OutOfBound);
91+
return Err(Error::MemOutOfBound);
9292
}
9393
// according to RISC-V instruction encoding, the lowest bit in PC will always be zero
9494
let instruction_cache_key = (pc >> 1) as usize % INSTRUCTION_CACHE_SIZE;

src/error.rs

Lines changed: 72 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,93 @@
1-
use std::error::Error as StdError;
2-
use std::io::{Error as IOError, ErrorKind};
3-
41
#[derive(Debug, PartialEq, Clone, Eq, Display)]
52
pub enum Error {
6-
#[display(fmt = "parse error")]
7-
ParseError,
8-
#[display(fmt = "unaligned page access")]
9-
Unaligned,
10-
#[display(fmt = "out of bound access")]
11-
OutOfBound,
12-
#[display(fmt = "max cycles exceeded")]
13-
InvalidCycles,
14-
#[display(fmt = "cycles overflow")]
3+
#[display(fmt = "aot error: dynasm ret {}", "_0")]
4+
AotDynasm(i32),
5+
#[display(fmt = "aot error: section is empty")]
6+
AotSectionIsEmpty,
7+
#[display(fmt = "aot error: section overlaps with another")]
8+
AotSectionOverlaps,
9+
#[display(fmt = "aot error: limit reached maximum dummy sections")]
10+
AotLimitReachedMaximumDummySections,
11+
#[display(fmt = "aot error: limit reached maximum labels")]
12+
AotLimitReachedMaximumLabels,
13+
#[display(fmt = "aot error: limit reached maximum sections")]
14+
AotLimitReachedMaximumSections,
15+
#[display(fmt = "aot error: limit reached maximum temp register")]
16+
AotLimitReachedMaximumTempRegisters,
17+
#[display(fmt = "aot error: out of bound due to not start of basic block")]
18+
AotOutOfBoundDueToNotStartOfBasicBlock,
19+
#[display(fmt = "asm error: {}", "_0")]
20+
Asm(u8),
21+
#[display(fmt = "cycles error: max cycles exceeded")]
22+
CyclesExceeded,
23+
#[display(fmt = "cycles error: overflow")]
1524
CyclesOverflow,
25+
#[display(fmt = "elf error: bits")]
26+
ElfBits,
27+
#[display(fmt = "elf error: {}", "_0")]
28+
ElfParseError(String),
29+
#[display(fmt = "elf error: segment is unreadable")]
30+
ElfSegmentUnreadable,
31+
#[display(fmt = "elf error: segment is writable and executable")]
32+
ElfSegmentWritableAndExecutable,
33+
#[display(fmt = "elf error: segment addr or size is wrong")]
34+
ElfSegmentAddrOrSizeError,
35+
// External error type is for the debugging tool of CKB-VM, it should not be
36+
// used in this project.
37+
#[display(fmt = "external error: {}", "_0")]
38+
External(String),
39+
#[display(fmt = "invalid syscall {}", "_0")]
40+
InvalidEcall(u64),
1641
#[display(
1742
fmt = "invalid instruction pc=0x{:x} instruction=0x{:x}",
1843
"pc",
1944
"instruction"
2045
)]
2146
InvalidInstruction { pc: u64, instruction: u32 },
22-
#[display(fmt = "invalid syscall {}", "_0")]
23-
InvalidEcall(u64),
24-
#[display(fmt = "invalid elf")]
25-
InvalidElfBits,
2647
#[display(fmt = "invalid operand {}", "_0")]
2748
InvalidOp(u16),
28-
#[display(fmt = "I/O error: {:?}", "_0")]
29-
IO(ErrorKind),
30-
#[display(fmt = "dynasm error {}", "_0")]
31-
Dynasm(i32),
32-
#[display(fmt = "assembly error {}", "_0")]
33-
Asm(u8),
34-
#[display(fmt = "limit reached")] // FIXME: Distinguish which limit
35-
LimitReached,
36-
#[display(fmt = "invalid permission")] // FIXME: Distinguish which permission
37-
InvalidPermission,
3849
#[display(fmt = "invalid version")]
3950
InvalidVersion,
51+
#[display(fmt = "I/O error: {:?} {}", "kind", "data")]
52+
IO {
53+
kind: std::io::ErrorKind,
54+
data: String,
55+
},
56+
#[display(fmt = "memory error: out of bound")]
57+
MemOutOfBound,
58+
#[display(fmt = "memory error: out of stack")]
59+
MemOutOfStack,
60+
#[display(fmt = "memory error: unaligned page access")]
61+
MemPageUnalignedAccess,
62+
#[display(fmt = "memory error: write on executable page")]
63+
MemWriteOnExecutablePage,
64+
#[display(fmt = "memory error: write on freezed page")]
65+
MemWriteOnFreezedPage,
4066
#[display(fmt = "unexpected error")]
41-
Unexpected,
67+
Unexpected(String),
4268
#[display(fmt = "unimplemented")]
4369
Unimplemented,
44-
// Unknown error type is for the debugging tool of CKB-VM, it should not be
45-
// used in this project.
46-
#[display(fmt = "external error: {}", "_0")]
47-
External(String),
4870
}
4971

50-
impl StdError for Error {}
72+
impl std::error::Error for Error {}
73+
74+
impl From<std::io::Error> for Error {
75+
fn from(error: std::io::Error) -> Self {
76+
Error::IO {
77+
kind: error.kind(),
78+
data: error.to_string(),
79+
}
80+
}
81+
}
82+
83+
impl From<goblin_v023::error::Error> for Error {
84+
fn from(error: goblin_v023::error::Error) -> Self {
85+
Error::ElfParseError(error.to_string())
86+
}
87+
}
5188

52-
impl From<IOError> for Error {
53-
fn from(error: IOError) -> Self {
54-
Error::IO(error.kind())
89+
impl From<goblin_v040::error::Error> for Error {
90+
fn from(error: goblin_v040::error::Error) -> Self {
91+
Error::ElfParseError(error.to_string())
5592
}
5693
}

src/instructions/common.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,9 +84,9 @@ pub fn addiw<Mac: Machine>(
8484
fn check_load_boundary<R: Register>(version0: bool, address: &R, bytes: u64) -> Result<(), Error> {
8585
if version0 {
8686
let address = address.to_u64();
87-
let end = address.checked_add(bytes).ok_or(Error::OutOfBound)?;
87+
let end = address.checked_add(bytes).ok_or(Error::MemOutOfBound)?;
8888
if end == RISCV_MAX_MEMORY as u64 {
89-
return Err(Error::OutOfBound);
89+
return Err(Error::MemOutOfBound);
9090
}
9191
}
9292
Ok(())

src/machine/aot/emitter.rs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ fn check_aot_result(result: c_int) -> Result<(), Error> {
142142
if result == 0 {
143143
Ok(())
144144
} else {
145-
Err(Error::Dynasm(result))
145+
Err(Error::AotDynasm(result))
146146
}
147147
}
148148

@@ -161,7 +161,7 @@ impl Default for TempRegisterAllocator {
161161
impl TempRegisterAllocator {
162162
pub fn next(&mut self) -> Result<usize, Error> {
163163
if self.next > MAXIMAL_TEMP_REGISTER {
164-
return Err(Error::OutOfBound);
164+
return Err(Error::AotLimitReachedMaximumTempRegisters);
165165
}
166166
let value = self.next;
167167
self.next += 1;
@@ -198,7 +198,7 @@ impl Emitter {
198198
pub fn new(labels: usize, version: u32) -> Result<Emitter, Error> {
199199
let aot = unsafe { aot_new(labels as u32, version) };
200200
if aot.is_null() {
201-
Err(Error::Dynasm(-1))
201+
Err(Error::AotDynasm(-1))
202202
} else {
203203
let emitter = Emitter {
204204
aot,
@@ -212,15 +212,15 @@ impl Emitter {
212212
let mut buffer_size: usize = 0;
213213
let result = unsafe { aot_link(self.aot, &mut buffer_size) };
214214
if result != 0 {
215-
return Err(Error::Dynasm(result));
215+
return Err(Error::AotDynasm(result));
216216
}
217217
Ok(buffer_size)
218218
}
219219

220220
pub fn encode(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
221221
let result = unsafe { aot_encode(self.aot, buffer.as_mut_ptr() as *mut c_void) };
222222
if result != 0 {
223-
return Err(Error::Dynasm(result));
223+
return Err(Error::AotDynasm(result));
224224
}
225225
Ok(())
226226
}
@@ -229,23 +229,23 @@ impl Emitter {
229229
let mut offset = 0;
230230
let result = unsafe { aot_getpclabel(self.aot, label, &mut offset as *mut u32) };
231231
if result != 0 {
232-
return Err(Error::Dynasm(result));
232+
return Err(Error::AotDynasm(result));
233233
}
234234
Ok(offset)
235235
}
236236

237237
pub fn emit_label(&mut self, label: u32) -> Result<(), Error> {
238238
let result = unsafe { aot_label(self.aot, label) };
239239
if result != 0 {
240-
return Err(Error::Dynasm(result));
240+
return Err(Error::AotDynasm(result));
241241
}
242242
Ok(())
243243
}
244244

245245
pub fn emit_add_cycles(&mut self, cycles: u64) -> Result<(), Error> {
246246
let result = unsafe { aot_add_cycles(self.aot, cycles) };
247247
if result != 0 {
248-
return Err(Error::Dynasm(result));
248+
return Err(Error::AotDynasm(result));
249249
}
250250
Ok(())
251251
}
@@ -266,7 +266,7 @@ impl Emitter {
266266
pc_write = Some(self.emit_value(value)?);
267267
}
268268
_ => {
269-
return Err(Error::Unexpected);
269+
return Err(Error::Unexpected(String::from("Unexpected write type")));
270270
}
271271
}
272272
}

src/machine/aot/mod.rs

Lines changed: 21 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -106,47 +106,45 @@ impl LabelGatheringMachine {
106106
use goblin_v023::container::Ctx;
107107
use goblin_v023::elf::{Header, SectionHeader};
108108

109-
let header = program.pread::<Header>(0).map_err(|_e| Error::ParseError)?;
110-
let container = header.container().map_err(|_e| Error::InvalidElfBits)?;
111-
let endianness = header.endianness().map_err(|_e| Error::InvalidElfBits)?;
109+
let header = program.pread::<Header>(0)?;
110+
let container = header.container().map_err(|_e| Error::ElfBits)?;
111+
let endianness = header.endianness().map_err(|_e| Error::ElfBits)?;
112112
if <Self as CoreMachine>::REG::BITS != if container.is_big() { 64 } else { 32 } {
113-
return Err(Error::InvalidElfBits);
113+
return Err(Error::ElfBits);
114114
}
115115
let ctx = Ctx::new(container, endianness);
116116
SectionHeader::parse(
117117
program,
118118
header.e_shoff as usize,
119119
header.e_shnum as usize,
120120
ctx,
121-
)
122-
.map_err(|_e| Error::ParseError)?
121+
)?
123122
.iter()
124123
.map(elf_adaptor::SectionHeader::from_v0)
125124
.collect()
126125
} else {
127126
use goblin_v040::container::Ctx;
128127
use goblin_v040::elf::{Header, SectionHeader};
129128

130-
let header = program.pread::<Header>(0).map_err(|_e| Error::ParseError)?;
131-
let container = header.container().map_err(|_e| Error::InvalidElfBits)?;
132-
let endianness = header.endianness().map_err(|_e| Error::InvalidElfBits)?;
129+
let header = program.pread::<Header>(0)?;
130+
let container = header.container().map_err(|_e| Error::ElfBits)?;
131+
let endianness = header.endianness().map_err(|_e| Error::ElfBits)?;
133132
if <Self as CoreMachine>::REG::BITS != if container.is_big() { 64 } else { 32 } {
134-
return Err(Error::InvalidElfBits);
133+
return Err(Error::ElfBits);
135134
}
136135
let ctx = Ctx::new(container, endianness);
137136
SectionHeader::parse(
138137
program,
139138
header.e_shoff as usize,
140139
header.e_shnum as usize,
141140
ctx,
142-
)
143-
.map_err(|_e| Error::ParseError)?
141+
)?
144142
.iter()
145143
.map(elf_adaptor::SectionHeader::from_v1)
146144
.collect()
147145
};
148146
if section_headers.len() > MAXIMUM_SECTIONS {
149-
return Err(Error::LimitReached);
147+
return Err(Error::AotLimitReachedMaximumSections);
150148
}
151149
let mut sections: Vec<(u64, u64)> = section_headers
152150
.iter()
@@ -164,14 +162,14 @@ impl LabelGatheringMachine {
164162
.collect();
165163
// Test there's no empty section
166164
if sections.iter().any(|(s, e)| s >= e) {
167-
return Err(Error::OutOfBound);
165+
return Err(Error::AotSectionIsEmpty);
168166
}
169167
// Test no section overlaps with one another. We first sort section
170168
// list by start, then we test if each end is equal or less than
171169
// the next start.
172170
sections.sort_by_key(|section| section.0);
173171
if sections.windows(2).any(|w| w[0].1 > w[1].0) {
174-
return Err(Error::OutOfBound);
172+
return Err(Error::AotSectionOverlaps);
175173
}
176174
// DefaultCoreMachine is only used here for loading ELF binaries
177175
// into memory.
@@ -195,7 +193,7 @@ impl LabelGatheringMachine {
195193
fn read_pc(&self) -> Result<u64, Error> {
196194
match &self.pc {
197195
Value::Imm(pc) => Ok(*pc),
198-
_ => Err(Error::Unexpected),
196+
_ => Err(Error::Unexpected(String::from("Unexpected value type"))),
199197
}
200198
}
201199

@@ -222,7 +220,7 @@ impl LabelGatheringMachine {
222220
}
223221
}
224222
if self.labels.len() > MAXIMUM_LABELS {
225-
return Err(Error::LimitReached);
223+
return Err(Error::AotLimitReachedMaximumLabels);
226224
}
227225
self.pc = Value::from_u64(next_pc);
228226
}
@@ -249,7 +247,7 @@ impl LabelGatheringMachine {
249247
// allow us to signal correct error and revert back
250248
// to assembly VM for those quirky programs.
251249
if !start_of_basic_block {
252-
return Err(Error::OutOfBound);
250+
return Err(Error::AotOutOfBoundDueToNotStartOfBasicBlock);
253251
}
254252
let mut dummy_end = pc + 2;
255253
while dummy_end < section_end && self.memory.execute_load16(dummy_end)? == 0
@@ -260,7 +258,7 @@ impl LabelGatheringMachine {
260258
// sections won't overlap with each other as well.
261259
self.dummy_sections.insert(pc, dummy_end);
262260
if self.dummy_sections.len() > MAXIMUM_DUMMY_SECTIONS {
263-
return Err(Error::LimitReached);
261+
return Err(Error::AotLimitReachedMaximumDummySections);
264262
}
265263
self.pc = Value::from_u64(dummy_end);
266264
}
@@ -270,7 +268,7 @@ impl LabelGatheringMachine {
270268
// A section must end a basic block, otherwise we would run into
271269
// out of bound error;
272270
if !start_of_basic_block {
273-
return Err(Error::OutOfBound);
271+
return Err(Error::AotOutOfBoundDueToNotStartOfBasicBlock);
274272
}
275273
debug_assert!(!self.labels.contains(&section_end));
276274
}
@@ -478,7 +476,7 @@ impl AotCompilingMachine {
478476
fn read_pc(&self) -> Result<u64, Error> {
479477
match &self.pc {
480478
Value::Imm(pc) => Ok(*pc),
481-
_ => Err(Error::Unexpected),
479+
_ => Err(Error::Unexpected(String::from("Unexpected value type"))),
482480
}
483481
}
484482

@@ -525,7 +523,7 @@ impl AotCompilingMachine {
525523
let pc = self.read_pc()?;
526524
// Emit succeeding PC write only
527525
if pc >= RISCV_MAX_MEMORY as u64 {
528-
return Err(Error::OutOfBound);
526+
return Err(Error::MemOutOfBound);
529527
}
530528
self.emitter.emit(&Write::Pc {
531529
value: Value::Imm(pc | ADDRESS_WRITE_ONLY_FLAG),
@@ -619,7 +617,7 @@ impl AotCompilingMachine {
619617

620618
fn optimize_pc(&self, pc: u64) -> Result<u64, Error> {
621619
if pc >= RISCV_MAX_MEMORY as u64 {
622-
return Err(Error::OutOfBound);
620+
return Err(Error::MemOutOfBound);
623621
}
624622
if pc < MAXIMUM_ENCODED_ADDRESS {
625623
if let Some(label) = self.addresses_to_labels.get(&pc) {

0 commit comments

Comments
 (0)