Skip to content

Commit e7d6e71

Browse files
committed
reorganize shims by platform
1 parent 0a803c9 commit e7d6e71

File tree

5 files changed

+328
-192
lines changed

5 files changed

+328
-192
lines changed

src/shims/foreign_items.rs

Lines changed: 34 additions & 192 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
mod windows;
2+
mod posix;
3+
14
use std::{convert::TryInto, iter};
25

36
use rustc_hir::def_id::DefId;
@@ -167,6 +170,30 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
167170
};
168171

169172
// Next: functions that return.
173+
match link_name {
174+
"__rust_maybe_catch_panic" => {
175+
this.handle_catch_panic(args, dest, ret)?;
176+
return Ok(None);
177+
}
178+
179+
_ => this.emulate_foreign_item_by_name(link_name, args, dest)?,
180+
};
181+
182+
this.dump_place(*dest);
183+
this.go_to_block(ret);
184+
185+
Ok(None)
186+
}
187+
188+
fn emulate_foreign_item_by_name(
189+
&mut self,
190+
link_name: &str,
191+
args: &[OpTy<'tcx, Tag>],
192+
dest: PlaceTy<'tcx, Tag>,
193+
) -> InterpResult<'tcx> {
194+
let this = self.eval_context_mut();
195+
let tcx = &{ this.tcx.tcx };
196+
170197
match link_name {
171198
"malloc" => {
172199
let size = this.read_scalar(args[0])?.to_machine_usize(this)?;
@@ -339,11 +366,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
339366
}
340367
}
341368

342-
"__rust_maybe_catch_panic" => {
343-
this.handle_catch_panic(args, dest, ret)?;
344-
return Ok(None);
345-
}
346-
347369
"memcmp" => {
348370
let left = this.read_scalar(args[0])?.not_undef()?;
349371
let right = this.read_scalar(args[1])?.not_undef()?;
@@ -399,143 +421,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
399421
}
400422
}
401423

402-
| "__errno_location"
403-
| "__error"
404-
=> {
405-
let errno_place = this.machine.last_error.unwrap();
406-
this.write_scalar(errno_place.to_ref().to_scalar()?, dest)?;
407-
}
408-
409-
"getenv" => {
410-
let result = this.getenv(args[0])?;
411-
this.write_scalar(result, dest)?;
412-
}
413-
414-
"unsetenv" => {
415-
let result = this.unsetenv(args[0])?;
416-
this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
417-
}
418-
419-
"setenv" => {
420-
let result = this.setenv(args[0], args[1])?;
421-
this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
422-
}
423-
424-
"getcwd" => {
425-
let result = this.getcwd(args[0], args[1])?;
426-
this.write_scalar(result, dest)?;
427-
}
428-
429-
"chdir" => {
430-
let result = this.chdir(args[0])?;
431-
this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
432-
}
433-
434-
| "open"
435-
| "open64"
436-
=> {
437-
let result = this.open(args[0], args[1])?;
438-
this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
439-
}
440-
441-
"fcntl" => {
442-
let result = this.fcntl(args[0], args[1], args.get(2).cloned())?;
443-
this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
444-
}
445-
446-
| "close"
447-
| "close$NOCANCEL"
448-
=> {
449-
let result = this.close(args[0])?;
450-
this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
451-
}
452-
453-
"read" => {
454-
let result = this.read(args[0], args[1], args[2])?;
455-
this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
456-
}
457-
458-
"write" => {
459-
let fd = this.read_scalar(args[0])?.to_i32()?;
460-
let buf = this.read_scalar(args[1])?.not_undef()?;
461-
let n = this.read_scalar(args[2])?.to_machine_usize(tcx)?;
462-
trace!("Called write({:?}, {:?}, {:?})", fd, buf, n);
463-
let result = if fd == 1 || fd == 2 {
464-
// stdout/stderr
465-
use std::io::{self, Write};
466-
467-
let buf_cont = this.memory.read_bytes(buf, Size::from_bytes(n))?;
468-
// We need to flush to make sure this actually appears on the screen
469-
let res = if fd == 1 {
470-
// Stdout is buffered, flush to make sure it appears on the screen.
471-
// This is the write() syscall of the interpreted program, we want it
472-
// to correspond to a write() syscall on the host -- there is no good
473-
// in adding extra buffering here.
474-
let res = io::stdout().write(buf_cont);
475-
io::stdout().flush().unwrap();
476-
res
477-
} else {
478-
// No need to flush, stderr is not buffered.
479-
io::stderr().write(buf_cont)
480-
};
481-
match res {
482-
Ok(n) => n as i64,
483-
Err(_) => -1,
484-
}
485-
} else {
486-
this.write(args[0], args[1], args[2])?
487-
};
488-
// Now, `result` is the value we return back to the program.
489-
this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
490-
}
491-
492-
| "lseek64"
493-
| "lseek"
494-
=> {
495-
let result = this.lseek64(args[0], args[1], args[2])?;
496-
this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
497-
}
498-
499-
"unlink" => {
500-
let result = this.unlink(args[0])?;
501-
this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
502-
}
503-
504-
"symlink" => {
505-
let result = this.symlink(args[0], args[1])?;
506-
this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
507-
}
508-
509-
"stat$INODE64" => {
510-
let result = this.stat(args[0], args[1])?;
511-
this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
512-
}
513-
514-
"lstat$INODE64" => {
515-
let result = this.lstat(args[0], args[1])?;
516-
this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
517-
}
518-
519-
"fstat$INODE64" => {
520-
let result = this.fstat(args[0], args[1])?;
521-
this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
522-
}
523424

524425
"rename" => {
525426
let result = this.rename(args[0], args[1])?;
526427
this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
527428
}
528429

529-
"clock_gettime" => {
530-
let result = this.clock_gettime(args[0], args[1])?;
531-
this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
532-
}
533-
534-
"gettimeofday" => {
535-
let result = this.gettimeofday(args[0], args[1])?;
536-
this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
537-
}
538-
539430
"strlen" => {
540431
let ptr = this.read_scalar(args[0])?.not_undef()?;
541432
let n = this.memory.read_c_str(ptr)?.len();
@@ -950,60 +841,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
950841
// which one it is.
951842
this.write_scalar(Scalar::from_int(which, this.pointer_size()), dest)?;
952843
}
953-
"WriteFile" => {
954-
let handle = this.read_scalar(args[0])?.to_machine_isize(this)?;
955-
let buf = this.read_scalar(args[1])?.not_undef()?;
956-
let n = this.read_scalar(args[2])?.to_u32()?;
957-
let written_place = this.deref_operand(args[3])?;
958-
// Spec says to always write `0` first.
959-
this.write_null(written_place.into())?;
960-
let written = if handle == -11 || handle == -12 {
961-
// stdout/stderr
962-
use std::io::{self, Write};
963-
964-
let buf_cont = this.memory.read_bytes(buf, Size::from_bytes(u64::from(n)))?;
965-
let res = if handle == -11 {
966-
io::stdout().write(buf_cont)
967-
} else {
968-
io::stderr().write(buf_cont)
969-
};
970-
res.ok().map(|n| n as u32)
971-
} else {
972-
eprintln!("Miri: Ignored output to handle {}", handle);
973-
// Pretend it all went well.
974-
Some(n)
975-
};
976-
// If there was no error, write back how much was written.
977-
if let Some(n) = written {
978-
this.write_scalar(Scalar::from_u32(n), written_place.into())?;
979-
}
980-
// Return whether this was a success.
981-
this.write_scalar(
982-
Scalar::from_int(if written.is_some() { 1 } else { 0 }, dest.layout.size),
983-
dest,
984-
)?;
985-
}
986844
"GetConsoleMode" => {
987845
// Everything is a pipe.
988846
this.write_null(dest)?;
989847
}
990-
"GetEnvironmentVariableW" => {
991-
// args[0] : LPCWSTR lpName (32-bit ptr to a const string of 16-bit Unicode chars)
992-
// args[1] : LPWSTR lpBuffer (32-bit pointer to a string of 16-bit Unicode chars)
993-
// lpBuffer : ptr to buffer that receives contents of the env_var as a null-terminated string.
994-
// Return `# of chars` stored in the buffer pointed to by lpBuffer, excluding null-terminator.
995-
// Return 0 upon failure.
996-
997-
// This is not the env var you are looking for.
998-
this.set_last_error(Scalar::from_u32(203))?; // ERROR_ENVVAR_NOT_FOUND
999-
this.write_null(dest)?;
1000-
}
1001-
"SetEnvironmentVariableW" => {
1002-
// args[0] : LPCWSTR lpName (32-bit ptr to a const string of 16-bit Unicode chars)
1003-
// args[1] : LPCWSTR lpValue (32-bit ptr to a const string of 16-bit Unicode chars)
1004-
// Return nonzero if success, else return 0.
1005-
throw_unsup_format!("can't set environment variable on Windows");
1006-
}
1007848
"GetCommandLineW" => {
1008849
this.write_scalar(
1009850
this.machine.cmd_line.expect("machine must be initialized"),
@@ -1018,13 +859,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
1018859
this.write_scalar(Scalar::from_bool(true), dest)?;
1019860
}
1020861

1021-
// We can't execute anything else.
1022-
_ => throw_unsup_format!("can't call foreign function: {}", link_name),
1023-
}
862+
_ => match this.tcx.sess.target.target.target_os.to_lowercase().as_str() {
863+
"linux" | "macos" => posix::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest)?,
864+
"windows" => windows::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest)?,
865+
target => throw_unsup_format!("The {} target platform is not supported", target),
866+
}
867+
};
1024868

1025-
this.dump_place(*dest);
1026-
this.go_to_block(ret);
1027-
Ok(None)
869+
Ok(())
1028870
}
1029871

1030872
/// Evaluates the scalar at the specified path. Returns Some(val)

src/shims/foreign_items/posix.rs

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
mod linux;
2+
mod macos;
3+
4+
use crate::*;
5+
use rustc::ty::layout::Size;
6+
7+
impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
8+
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
9+
fn emulate_foreign_item_by_name(
10+
&mut self,
11+
link_name: &str,
12+
args: &[OpTy<'tcx, Tag>],
13+
dest: PlaceTy<'tcx, Tag>,
14+
) -> InterpResult<'tcx> {
15+
let this = self.eval_context_mut();
16+
let tcx = &{ this.tcx.tcx };
17+
18+
match link_name {
19+
// Environment related shims
20+
"getenv" => {
21+
let result = this.getenv(args[0])?;
22+
this.write_scalar(result, dest)?;
23+
}
24+
25+
"unsetenv" => {
26+
let result = this.unsetenv(args[0])?;
27+
this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
28+
}
29+
30+
"setenv" => {
31+
let result = this.setenv(args[0], args[1])?;
32+
this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
33+
}
34+
35+
"getcwd" => {
36+
let result = this.getcwd(args[0], args[1])?;
37+
this.write_scalar(result, dest)?;
38+
}
39+
40+
"chdir" => {
41+
let result = this.chdir(args[0])?;
42+
this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
43+
}
44+
45+
// File related shims
46+
"fcntl" => {
47+
let result = this.fcntl(args[0], args[1], args.get(2).cloned())?;
48+
this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
49+
}
50+
51+
"read" => {
52+
let result = this.read(args[0], args[1], args[2])?;
53+
this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
54+
}
55+
56+
"write" => {
57+
let fd = this.read_scalar(args[0])?.to_i32()?;
58+
let buf = this.read_scalar(args[1])?.not_undef()?;
59+
let n = this.read_scalar(args[2])?.to_machine_usize(tcx)?;
60+
trace!("Called write({:?}, {:?}, {:?})", fd, buf, n);
61+
let result = if fd == 1 || fd == 2 {
62+
// stdout/stderr
63+
use std::io::{self, Write};
64+
65+
let buf_cont = this.memory.read_bytes(buf, Size::from_bytes(n))?;
66+
// We need to flush to make sure this actually appears on the screen
67+
let res = if fd == 1 {
68+
// Stdout is buffered, flush to make sure it appears on the screen.
69+
// This is the write() syscall of the interpreted program, we want it
70+
// to correspond to a write() syscall on the host -- there is no good
71+
// in adding extra buffering here.
72+
let res = io::stdout().write(buf_cont);
73+
io::stdout().flush().unwrap();
74+
res
75+
} else {
76+
// No need to flush, stderr is not buffered.
77+
io::stderr().write(buf_cont)
78+
};
79+
match res {
80+
Ok(n) => n as i64,
81+
Err(_) => -1,
82+
}
83+
} else {
84+
this.write(args[0], args[1], args[2])?
85+
};
86+
// Now, `result` is the value we return back to the program.
87+
this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
88+
}
89+
90+
"unlink" => {
91+
let result = this.unlink(args[0])?;
92+
this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
93+
}
94+
95+
"symlink" => {
96+
let result = this.symlink(args[0], args[1])?;
97+
this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
98+
}
99+
100+
_ => {
101+
match this.tcx.sess.target.target.target_os.to_lowercase().as_str() {
102+
"linux" => linux::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest)?,
103+
"macos" => macos::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest)?,
104+
_ => unreachable!(),
105+
}
106+
}
107+
};
108+
109+
Ok(())
110+
}
111+
}

0 commit comments

Comments
 (0)