Skip to content

Commit 8204188

Browse files
committed
Extract elf module.
- Add tests to the module. - Include code owners. Signed-off-by: David Calavera <david.calavera@gmail.com>
1 parent a04922d commit 8204188

File tree

7 files changed

+107
-80
lines changed

7 files changed

+107
-80
lines changed

.github/CODEOWNERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
* @calavera

.github/pull_request_template.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
### Summary
2+
3+
### Test plan
4+
5+
### Relevant links (GH issues, bugsnag, etc.) or a picture of cute animal

src/elf.rs

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
use goblin::{elf::sym, elf::Elf, error::Error};
2+
3+
const RUST_PERSONALITY: &str = "rust_eh_personality";
4+
const GO_SECTION: &str = ".note.go.buildid";
5+
6+
#[derive(Debug, PartialEq)]
7+
pub enum Runtime {
8+
Go,
9+
Rust,
10+
}
11+
12+
pub fn detect(data: &[u8]) -> Result<Option<Runtime>, Error> {
13+
let elf = match Elf::parse(data) {
14+
Ok(elf) => elf,
15+
_ => return Ok(None),
16+
};
17+
18+
for s in elf.shdr_strtab.to_vec()? {
19+
if s == GO_SECTION {
20+
return Ok(Some(Runtime::Go));
21+
}
22+
}
23+
24+
for s in elf.strtab.to_vec()? {
25+
if s == RUST_PERSONALITY {
26+
return Ok(Some(Runtime::Rust));
27+
}
28+
}
29+
30+
for s in elf.syms.iter() {
31+
if s.is_function() && s.st_bind() == sym::STB_GLOBAL {
32+
if let Some(Ok(sym_name)) = elf.strtab.get(s.st_name) {
33+
if sym_name == RUST_PERSONALITY {
34+
return Ok(Some(Runtime::Rust));
35+
}
36+
}
37+
}
38+
}
39+
40+
Ok(None)
41+
}
42+
43+
#[cfg(test)]
44+
mod tests {
45+
use super::*;
46+
47+
#[test]
48+
fn test_detect_go_runtime() {
49+
let buffer =
50+
std::fs::read("tests/data/hello-world-go").expect("failed to load binary file");
51+
52+
let runtime = detect(&buffer)
53+
.expect("failed to detect runtime")
54+
.expect("failed to return some runtime");
55+
assert_eq!(Runtime::Go, runtime);
56+
}
57+
58+
#[test]
59+
fn test_detect_rust_runtime() {
60+
let buffer =
61+
std::fs::read("tests/data/hello-world-rs").expect("failed to load binary file");
62+
63+
let runtime = detect(&buffer)
64+
.expect("failed to detect runtime")
65+
.expect("failed to return some runtime");
66+
assert_eq!(Runtime::Rust, runtime);
67+
}
68+
69+
#[test]
70+
fn test_detect_ignores_invalid_file() {
71+
let buffer =
72+
std::fs::read("tests/data/hello-world-text").expect("failed to load binary file");
73+
74+
let runtime = detect(&buffer).expect("failed to detect runtime");
75+
assert_eq!(None, runtime);
76+
}
77+
}

src/lib.rs

Lines changed: 23 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
use goblin::{elf::sym, elf::Elf};
2-
3-
mod utils;
1+
mod elf;
42

53
use wasm_bindgen::prelude::*;
64

@@ -10,54 +8,36 @@ use wasm_bindgen::prelude::*;
108
#[global_allocator]
119
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
1210

13-
const RUST_PERSONALITY: &str = "rust_eh_personality";
14-
const GO_SECTION: &str = ".note.go.buildid";
15-
1611
#[wasm_bindgen]
17-
#[derive(Debug, PartialEq)]
1812
pub enum Runtime {
1913
Go,
2014
Rust,
2115
}
2216

23-
#[wasm_bindgen(catch)]
24-
pub fn detect(data: &[u8]) -> Result<Option<Runtime>, JsValue> {
25-
utils::set_panic_hook();
26-
27-
let elf = match Elf::parse(data) {
28-
Ok(elf) => elf,
29-
_ => return Ok(None),
30-
};
31-
32-
for s in elf
33-
.shdr_strtab
34-
.to_vec()
35-
.map_err(|e| format!("error reading symbols: {}", e))?
36-
{
37-
if s == GO_SECTION {
38-
return Ok(Some(Runtime::Go));
39-
}
40-
}
41-
42-
for s in elf
43-
.strtab
44-
.to_vec()
45-
.map_err(|e| format!("error reading sections: {}", e))?
46-
{
47-
if s == RUST_PERSONALITY {
48-
return Ok(Some(Runtime::Rust));
17+
impl From<elf::Runtime> for Runtime {
18+
fn from(rt: elf::Runtime) -> Self {
19+
match rt {
20+
elf::Runtime::Go => Runtime::Go,
21+
elf::Runtime::Rust => Runtime::Rust,
4922
}
5023
}
24+
}
5125

52-
for s in elf.syms.iter() {
53-
if s.is_function() && s.st_bind() == sym::STB_GLOBAL {
54-
if let Some(Ok(sym_name)) = elf.strtab.get(s.st_name) {
55-
if sym_name == RUST_PERSONALITY {
56-
return Ok(Some(Runtime::Rust));
57-
}
58-
}
59-
}
60-
}
26+
#[wasm_bindgen(catch)]
27+
pub fn detect(data: &[u8]) -> Result<Option<Runtime>, JsValue> {
28+
set_panic_hook();
29+
elf::detect(data)
30+
.map_err(|e| JsValue::from(format!("error reading elf metadata: {}", e)))
31+
.map(|o| o.map(Runtime::from))
32+
}
6133

62-
Ok(None)
34+
fn set_panic_hook() {
35+
// When the `console_error_panic_hook` feature is enabled, we can call the
36+
// `set_panic_hook` function at least once during initialization, and then
37+
// we will get better error messages if our code ever panics.
38+
//
39+
// For more details see
40+
// https://github.com/rustwasm/console_error_panic_hook#readme
41+
#[cfg(feature = "console_error_panic_hook")]
42+
console_error_panic_hook::set_once();
6343
}

src/utils.rs

Lines changed: 0 additions & 10 deletions
This file was deleted.

tests/data/hello-world-text

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Hello, world!

tests/node.rs

Lines changed: 0 additions & 27 deletions
This file was deleted.

0 commit comments

Comments
 (0)