-
Notifications
You must be signed in to change notification settings - Fork 673
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add more ptrace_* wrappers #666
Conversation
Hi, pub enum Register {
SysArgNum,
SysArg1,
SysArg2,
...
} and then use #[cfg(all(target_os = "linux", any(target_arch = "x86_64")))]
#[inline]
pub fn get_reg(regs: &user_regs_struct, register: Register) -> c_long {
match register {
SysArgNum => regs.orig_rax,
SysArg1 => regs.rdi,
SysArg2 => regs.rsi,
...
}
} As it is implemented in this PR, the For /// Copy all `tracee`'s general purpose registers into a dedicated cache.
/// Returns either `Ok(regs)` or `Err(Sys(errno))` or `Err(InvalidPath)`.
#[inline]
pub fn fetch_regs(pid: pid_t) -> Result<user_regs_struct> {
let mut regs: user_regs_struct = unsafe { mem::zeroed() };
let p_regs: *mut c_void = &mut regs as *mut _ as *mut c_void;
ptrace(PTRACE_GETREGS, pid, null_mut(), p_regs)?;
Ok(regs)
} See here how to use all this (though I've implemented it like a macro so that it's faster, it can be converted to functions with big matches). |
@vincenthage for me this could be an extra feature. I think that our wrappers should support all registers, since it's what raw How did you manage to get the |
I don't understand your question, as Nix's wrappers should indeed support all registers, but I wonder if a list of field names, where some of them wouldn't be used (or even exist?) depending on the processor type, is a good solution. |
@vincenthage see the first post. (I tried to use...) And even if we did as you suggest: what if the user requests the 3rd argument when we have a syscall which only accepts 2? Or uses that after We could have an extra wrapper to answer the question what is the register is used for storing nth argument, but I'd treat it as an extra feature. @Susurrus, what do you think? I'd suggest we left this as it is and focus on another thing: do we declare |
Let's just start again so that we agree on the basics (it will also be useful for anyone looking into this the first time). pub enum Register {
SysArgNum,
SysArg1,
SysArg2,
SysArg3,
SysArg4,
SysArg5,
SysArg6,
SysArgResult,
StackPointer,
InstrPointer,
RtldFini,
StateFlags,
UserArg1
} Each of them corresponds to a certain field of Every time the tracee is stopped, you can get the content of the syscall by 2 ways (let's say we want the 1st argument):
Now, if we agree on all this:
The Again, the Now, it all depends on what you mean by a high-level wrapper. But in my opinion, a high-level wrapper shouldn't involve having the user manipulate offsets to find the arguments of a syscall. What I propose is directly giving a translated version of The best intermediate might be a let regs = fetch_regs(pid)?;
let sysnum = get_reg!(regs, SysArgNum) but also writing: let new_regs = regs.clone();
get_reg!(new_regs, SysArgNum) = 42; and this could be allied with a function and a |
On a side note, there is this offset macro that might work for your wrap, but it would require |
All the members of the Moreover, I don't see a And your suggested approach with The whole point of these high-level wrappers is that they wrap the existing, atrocious My idea is: add a |
You win. The lighter the wrap, the better anyway. About |
Is this behavior documented? Let's get down to the other issue: what about I asked a related question on users.rust-lang.org: https://users.rust-lang.org/t/when-should-we-mark-our-functions-unsafe/11834 |
All
It might actually be simpler to make all |
Marked that. And one more thing about the types. The |
This won't be merged until we figure out if those constants can be added to libc and get them added if so. We try not to define any FFI values or functions within |
What do you think of this: use std::ptr;
use libc::user_regs_struct;
use nix::sys::ptrace::ptrace::PTRACE_PEEKUSER;
pub type UserRegisters = user_regs_struct;
// the one in macros.rs
macro_rules! offset_of {
($ty:ty, $field:ident) => {
&(*(0 as *const $ty)).$field as *const _ as usize
}
}
macro_rules! peekuser {
($pid:expr, $reg:ident) => {
{
let reg_offset = unsafe {offset_of!(UserRegisters, $reg)} as *mut c_void;
ptrace(PTRACE_PEEKUSER, $pid, reg_offset, ptr::null_mut())
}
}
} which can be used like this: #[test]
fn test_peekuser() {
let pid = -1;
let reg_value = peekuser!(pid, r15);
assert!(reg_value.is_err());
} whereas using an non existing register field is impossible: peekuser!(pid, r9999); yields: error[E0609]: no field `r9999` on type `libc::user_regs_struct`
--> src/register/regs.rs:80:64
|
80 | let reg_offset = unsafe {offset_of!(UserRegisters, $reg)} as *mut c_void;
| ^^^^ did you mean `r9`?
...
100 | let reg_value = peekuser!(pid, r9999);
| --------------------- in this macro invocation
error: aborting due to previous error(s) With this, no need for a wrapper for each version of |
Also, @marmistrz, from what I gathered the size of Though, I agree that a light wrapper (like edit: Also found out that the return value of ptrace should be |
Yeah, I like it! :) This one's cross platform, the API is nice. Should I try adding the offsets to libc nevertheless?
I'll ask on the Rust forum about the return types, I don't really like the idea of leaking C types to Rust. The ptrace API will not be portable anyway. /edit: There's a small problem with the macro.... From
|
There are safe versions of the About replacing |
Version 2: macro_rules! offset_of {
($ty:tt, $field:ident) => {
{
let base: $ty = unsafe { ::std::mem::uninitialized() };
let offset_field = &(*(&base as *const $ty)).$field as *const _ as usize;
let offset_base = (&base as *const $ty) as *const _ as usize;
let offset = offset_field - offset_base;
::std::mem::forget(base);
offset
}
}
} This one uses an instance of the structure to calculate the offset. If the compiler doesn't optimise it into a constant, we can use |
Does |
I noticed another problem: depending on the context we may want to put a signed or unsigned value into the register. I'm not so sure if a cast to |
First of all, I didn't add In my new test it complains about |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A variety of minor changes are necessary. Please also run cargo doc --no-deps --open
to look at the resulting documentation and make sure it's pretty.
This also needs a rebase due to the latest changes (some which affect ptrace)
src/sys/ptrace.rs
Outdated
type Word = usize; | ||
|
||
/// Makes the `PTRACE_SYSCALL` request to ptrace | ||
pub fn syscall(pid: Pid) -> Result<()> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be called ptrace_syscall
, we're prefixing our helper functions with ptrace_
to make it more clear. syscall
is already a POSIX function, so we don't want any confusion here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If it has to, I'll change it. But IMHO what I do now is cleaner. With my approach you just use nix::sys::ptrace
and call it like ptrace::syscall()
, with the suggested approach: use nix::sys::ptrace::{ /* an endless list of imports */ }
or you have to use a star, which is not a great idea in general.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a good point as these are all namespaced unlike in C. Could you have a separate commit then that renames the existing ptrace_*
wrappers? That'll have to be documented in the CHANGELOG entry as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FYI I just meant a separate commit within this PR, not a new PR. But that's fine too.
src/sys/ptrace.rs
Outdated
use super::*; | ||
|
||
#[test] | ||
fn test_types() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please document why this test is necessary.
src/sys/ptrace.rs
Outdated
ptrace(ptrace::PTRACE_PEEKDATA, pid, addr as *mut c_void, ptr::null_mut()).map(|r| r as Word) | ||
} | ||
|
||
/// Makes the `PTRACE_PEEKDATA` request to ptrace |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comment is wrong.
src/sys/ptrace.rs
Outdated
|
||
/// Makes the `PTRACE_PEEKDATA` request to ptrace | ||
/// | ||
/// This function allows to access arbitrary data in the traced process |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Put this under a # Safety
section, which is a special section understood by rustdoc
src/sys/ptrace.rs
Outdated
} | ||
|
||
/// Sets the process as traceable with `PTRACE_TRACEME` | ||
pub fn traceme() -> Result<()> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again, should be ptrace_traceme
src/sys/ptrace.rs
Outdated
/// Sets the process as traceable with `PTRACE_TRACEME` | ||
pub fn traceme() -> Result<()> { | ||
unsafe { | ||
ptrace( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please put first argument on first line and align subsequent arguments with it only if they take up more than 99 columns of space.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I ran rustfmt
on the code (commit 2a295c6) and it's how rustfmt does it.
src/sys/ptrace.rs
Outdated
@@ -140,3 +150,110 @@ pub fn ptrace_setsiginfo(pid: Pid, sig: &siginfo_t) -> Result<()> { | |||
Err(e) => Err(e), | |||
} | |||
} | |||
|
|||
//-------------------------- Second part: a high-level wrapper for ptrace ----------------------// |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These comments need to be removed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's wrong with them? They clearly separate the sections
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
They're ugly mostly, the code has a sane ordering and these comments are mostly clutter. Generally source files are written so that low level stuff is at the top and high-level stuff is at the bottom. This is a convention from the C days when declarations had to be in order. It's not necessary in Rust, but it's still followed generally.
src/sys/ptrace.rs
Outdated
|
||
//-------------------------- Second part: a high-level wrapper for ptrace ----------------------// | ||
|
||
#[cfg(target_arch = "x86_64")] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is why your tests are failing, you need to either limit peekuser()
to x86_64, since that's the only play this register is defined for, or expand Register
to more platforms.
You can edit the title as well, feel free to change it to something more appropriate. The previous title didn't help me know which issue this was when reading it, so I changed it.
It's as the error says, |
That's a good point as these are all namespaced unlike in C. Could you
have a separate commit then that renames the existing |ptrace_*|
wrappers? That'll have to be documented in the CHANGELOG entry as well.
Should I do it before this one gets merged?
|
Yes, because otherwise it's a consistency issue. You should have 3 commits here, the first is renaming the existing functions, the second is all of your changes, and the third is updating the CHANGELOG. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should also extend the list of UnsupportedOperations
reported by ptrace
to include the new wrappers you've introduced. We'd like to get people using the wrappers instead of the raw ptrace()
function.
src/sys/ptrace.rs
Outdated
type Word = usize; | ||
|
||
/// Makes the `PTRACE_SYSCALL` request to ptrace | ||
pub fn syscall(pid: Pid) -> Result<()> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FYI I just meant a separate commit within this PR, not a new PR. But that's fine too.
src/sys/ptrace.rs
Outdated
@@ -140,3 +149,124 @@ pub fn ptrace_setsiginfo(pid: Pid, sig: &siginfo_t) -> Result<()> { | |||
Err(e) => Err(e), | |||
} | |||
} | |||
|
|||
#[cfg(target_arch = "x86_64")] | |||
// We're going to export it anyway |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comments come before attributes.
src/sys/ptrace.rs
Outdated
@@ -68,9 +73,13 @@ mod ffi { | |||
} | |||
} | |||
|
|||
/// Performs a ptrace request. If the request in question is provided by a specialised function | |||
/// A low-level wrapper for `ptrace`. If available, the higher-level wrappers should be considered instead. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be a short one-line description with a blank line and then more description below.
src/sys/ptrace.rs
Outdated
/// | ||
/// # Safety | ||
/// This function allows to access arbitrary data in the traced process | ||
/// and may crash the inferior if used incorrectly and is thus marked `unsafe`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is "the inferior" here? That doesn't read right to me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, gdb always talks about the inferior - the process that's spawned by gdb and traced.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this the term used on the man pages? That's the reference docs we link to, so we should use that terminology. I believe they use "tracer" and "tracee".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@marmistrz Any comment on this?
src/sys/ptrace.rs
Outdated
/// Makes the `PTRACE_PEEKDATA` request to ptrace | ||
/// | ||
/// # Safety | ||
/// This function allows to access arbitrary data in the traced process |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be "allows for accessing"
src/sys/ptrace.rs
Outdated
/// Makes the `PTRACE_POKEDATA` request to ptrace | ||
/// | ||
/// # Safety | ||
/// This function allows to access arbitrary data in the traced process |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same grammar nitpicks as above.
src/sys/ptrace.rs
Outdated
/// This function allows to access arbitrary data in the traced process | ||
/// and may crash the inferior or introduce race conditions if used | ||
/// incorrectly and is thus marked `unsafe`. | ||
pub unsafe fn pokedata(pid: Pid, addr: usize, val: Word) -> Result<()> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd like to see some tests for these if possible, even if they just return errors, if for no other reason than to test the ergonomics of our wrappers. For example here I don't know how you'd generate addr
since it's supposed to be a raw pointer type.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One simple test that doesn't require any memory allocation is to cancel a syscall by changing its syscall number to 0 during the enter stage, and then reverting it during the exit stage.
95d39a1
to
f58049a
Compare
is it ok now? |
src/sys/ptrace.rs
Outdated
fn ptrace_peek(request: Request, pid: Pid, addr: *mut c_void, data: *mut c_void) -> Result<c_long> { | ||
let ret = unsafe { | ||
unsafe fn ptrace_peek(request: Request, pid: Pid, addr: *mut c_void, data: *mut c_void) -> Result<c_long> { | ||
let ret = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's no reason to have this in braces, just make these two separate lines instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed that and reformatted to avoid exceeding 80 columns of length.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Biggest question is does it make more sense to make syscall*!
a method on Register
? There's a runtime overhead but it clarifies the docs and unifies things a little nicer. This was discussed somewhat in the original discussion I believe, so it may already have been considered.
src/sys/ptrace.rs
Outdated
ptr::null_mut(), | ||
ptr::null_mut(), | ||
).map(|_| ()) // ignore the useless return value | ||
ptrace_other(Request::PTRACE_ATTACH, pid, ptr::null_mut(), ptr::null_mut()).map(|_| ()) // ignore the useless return value |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This line's too long, but it's obvious what the final map()
is doing, so just remove the comment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
src/sys/ptrace.rs
Outdated
#[cfg(target_arch = "x86_64")] | ||
#[allow(non_camel_case_types)] | ||
#[derive(Debug, PartialEq)] | ||
/// Represents all possible ptrace-accessible registers on x86_64 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please move this comment before the #[cfg...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
src/sys/ptrace.rs
Outdated
#[derive(Debug, PartialEq)] | ||
/// Represents all possible ptrace-accessible registers on x86_64 | ||
pub enum Register { | ||
R15 = 8 * ::libc::R15 as isize, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd prefer to have all these registers documented, which I think I requested in my earlier review. Could you do this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please, R15 is just an... R15 register. If someone's using ptrace, it they have to know what the register does anyway.
I don't see any added value in documenting it as
R15 = 8 * ::libc::R15 as isize, /// the R15 register
People using ptrace
are not kids.
src/sys/ptrace.rs
Outdated
/// | ||
/// 0th argument is considered to be the syscall number. | ||
/// Please note that these mappings are only valid for 64-bit programs. | ||
/// Use syscall_arg32 for tracing 32-bit programs instead. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please link to syscall_arg32
and put it in backticks. You can see how we link to other types by looking at src/sys/wait.rs:57
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
/// # } | ||
#[cfg(target_arch = "x86")] | ||
#[macro_export] | ||
macro_rules! syscall_arg { |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
/// ``` | ||
/// # #[macro_use] extern crate nix; | ||
/// # fn main() { | ||
/// assert_eq!(syscall_arg!(1), nix::sys::ptrace::Register::RDI); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This isn't a good example because a) it uses an assert (this should be a test if anything) and b) it doesn't demonstrate actual usage. No one is going to write code like this. How would you actually use syscall_arg!
in practice? As an argument to pokeuser
, right? This applies to all 3 of these macros.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's similar to what the official docs do: https://doc.rust-lang.org/std/fmt/fn.format.html
And it's not trivial to assert in doc tests without all the boilterplate.
The main thing here is to explain the syntax. The rest is obvious.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have no issues with the boilerplate, I'm suggesting that examples be a demonstration to the user of how this is used. While yes, you show the syntax to use with this macro, we can do better by showing it in a broader context, where it's used as an argument to one of the ptrace
wrapper functions. So I suggest you copy one of the lines where this is used from the test code (like as an argument to pokedata
) and stick it here and make this code block no_run
so it will at least be compile-checked.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs a valid struct Pid
, which has to be obtained from somewhere (a user will wonder what the heck is pid
here). What about just mentioning that the purpose is to achieve arch-independent syscall argument lookups?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can leave the boilerplate commented-out here as well. Do what you need to do to get it to compile, but having something like ptrace::peekuser(child, syscall_arg!(0))
As the example would be better in my opinion.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you need valid values and can't get them, just mark this as only a compilation test by using ```no_run` to start the example. The point of an example isn't to test the code it's to show the user how they might use the code and provide a little additional context. The example I provided above, when annotated with a little description, would suit both of those goals.
test/sys/test_ptrace.rs
Outdated
@@ -1,9 +1,14 @@ | |||
#![cfg(all(target_os = "linux", any(target_arch = "x86", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is already specified in test/sys/mod.rs
, why are you respecifying it here? You probably want to restrict just your new tests a little more rather than the whole module.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I don't remember. Fixed that.
I think that having this compile-time checked is a superior benefit. Could we please get it merged before Friday? I want to rebase a project onto the upstreamed functions before I go on a short vacation. |
src/sys/ptrace.rs
Outdated
#[cfg(target_arch = "x86_64")] | ||
#[allow(non_camel_case_types)] | ||
#[derive(Debug, PartialEq)] | ||
pub enum Register { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a logical ordering to these registers? I would at least expect R10..R15 to be in order and they're not. I'm not certain how the docs for these are generally arranged, but maybe we can do a better grouping here?
Additionally is there no reference documentation we can link to here to give users more background on these registers? Some canonical reference? The kernel has some docs that touch on this here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, that's the order from user_regs_struct
. Please, don't make nix an operating systems kindergarten. As said in another comment, there's a lot of other things that you need to know, to be able to use ptrace
.
/// ``` | ||
/// # #[macro_use] extern crate nix; | ||
/// # fn main() { | ||
/// assert_eq!(syscall_arg!(1), nix::sys::ptrace::Register::RDI); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have no issues with the boilerplate, I'm suggesting that examples be a demonstration to the user of how this is used. While yes, you show the syntax to use with this macro, we can do better by showing it in a broader context, where it's used as an argument to one of the ptrace
wrapper functions. So I suggest you copy one of the lines where this is used from the test code (like as an argument to pokedata
) and stick it here and make this code block no_run
so it will at least be compile-checked.
Yep we can shoot for Friday and I think it's doable given we're mostly fixing little things at this point and I think the API is solid. |
RCX = 8 * ::libc::RCX as isize, | ||
RDX = 8 * ::libc::RDX as isize, | ||
RSI = 8 * ::libc::RSI as isize, | ||
RDI = 8 * ::libc::RDI as isize, |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
@Susurrus, please remember I'm UTC+2. I'd like to have it merged before Friday morning UTC+2. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, I meant to get to this last night but this is about the busiest week to get me to review things. So here's what should be a final batch of comments.
test/sys/test_ptrace.rs
Outdated
@@ -55,6 +158,8 @@ fn test_ptrace_cont() { | |||
use nix::unistd::fork; | |||
use nix::unistd::ForkResult::*; | |||
|
|||
let _m = ::FORK_MTX.lock().expect("Mutex got poisoned by another test"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is unrelated to all the other changes in this commit. Can you break this out into a separate commit?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I simply removed that for now. This can be added once the changes are squashed.
src/sys/ptrace.rs
Outdated
/// | ||
/// # Safety | ||
/// This function allows to access arbitrary data in the traced process | ||
/// and may crash the inferior if used incorrectly and is thus marked `unsafe`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@marmistrz Any comment on this?
/// # } | ||
#[cfg(target_arch = "x86")] | ||
#[macro_export] | ||
macro_rules! syscall_arg { |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
/// ``` | ||
/// # #[macro_use] extern crate nix; | ||
/// # fn main() { | ||
/// assert_eq!(syscall_arg!(1), nix::sys::ptrace::Register::RDI); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can leave the boilerplate commented-out here as well. Do what you need to do to get it to compile, but having something like ptrace::peekuser(child, syscall_arg!(0))
As the example would be better in my opinion.
WaitStatus::PtraceSyscall(child) => { | ||
match syscall_no { | ||
None => { | ||
let no = ptrace::peekuser(child, syscall_arg!(0)).unwrap(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it possible to run the tests as a 32-bit process on a 64-bit architecture and so these tests will fail because they use syscall_arg!
? If so we should either fix the tests to work regardless or disable the tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you address my question here?
RCX = 8 * ::libc::RCX as isize, | ||
RDX = 8 * ::libc::RDX as isize, | ||
RSI = 8 * ::libc::RSI as isize, | ||
RDI = 8 * ::libc::RDI as isize, |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
@marmistrz Looked like we were pretty close on this. Sorry we missed your original target date, but any interest in polishing this off for merging? |
Interest yes, but unfortunately severe lack of time. This will have to wait for another week or two at least. |
is this PR still relevant? |
@marmistrz Who is supposed to answer that question? As you proposed this PR, I guess I'd ask you if it's still relevant: do you want it in nix and are you willing to finish polishing it off to merge? If no to either of those, let's go ahead and close this. |
@Susurrus more precisely, I'm asking if the changes accepted during the last half a year have not obsoleted this PR. In the meantime the features could have been partially implemeneted or the API may have gone in a completely different direction, which could make the proposed API out place. I'll have a while to polish it off, but not overly much, so I want to get it merged with as little hassle as possible. |
I don't know what's happened with the API, thought the CHANGELOG is comprehensive and I'd suggest you check there first, though |
Fixed the things mentioned in the last review. Should I now squash it all into one commit
this can't be easily asserted, so I'd leave it as it is. |
@Susurrus tests pass, can we merge? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, we're pretty close here. I think the examples could be improved to give users a more real-world use case to understand our API here.
@@ -80,6 +80,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). | |||
([#739](https://github.com/nix-rust/nix/pull/739)) | |||
- Expose `signalfd` module on Android as well. | |||
([#739](https://github.com/nix-rust/nix/pull/739)) | |||
- Added nix::sys::ptrace::detach. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be removed, I assume it was a rebase error.
- Added specialized wrappers: `sys::ptrace::{peek, poke}{user, data}` | ||
and macros: `syscall_arg`, `syscall_arg32` for register-to-argument | ||
mappings. Using the matching routines | ||
with `sys::ptrace::ptrace` is now deprecated. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's some weird indentation going on with this line.
/// ``` | ||
/// # #[macro_use] extern crate nix; | ||
/// # fn main() { | ||
/// assert_eq!(syscall_arg!(1), nix::sys::ptrace::Register::RDI); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you need valid values and can't get them, just mark this as only a compilation test by using ```no_run` to start the example. The point of an example isn't to test the code it's to show the user how they might use the code and provide a little additional context. The example I provided above, when annotated with a little description, would suit both of those goals.
/// ``` | ||
/// # #[macro_use] extern crate nix; | ||
/// # fn main() { | ||
/// assert_eq!(syscall_arg!(1), nix::sys::ptrace::Register::RDI); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please improve this example in line with my comments about syscall_arg32!
.
//! Interface for `ptrace` | ||
//! | ||
//! For detailed description of the ptrace requests, consult [`ptrace`(2)]. | ||
//! [`ptrace`(2)]: http://man7.org/linux/man-pages/man2/ptrace.2.html |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't render correctly on Rust 1.25.0.
WaitStatus::PtraceSyscall(child) => { | ||
match syscall_no { | ||
None => { | ||
let no = ptrace::peekuser(child, syscall_arg!(0)).unwrap(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you address my question here?
Let's close it. This PR is over two years old and the API has substantially change since this PR was opened. |
Btw. I think that the
nix::sys::ptrace::ptrace
function should be marked as unsafe. It allows to change arbitrary registers and addresses in a child process - just as dereferencing a pointer is unsafe in Rust.I was unable to use
libc::user_regs_struct
, the Rust compiler complains that it can't find the members.By the way, we're missing
PTRACE_GETREGS
.I tried to use the
user_regs_struct
in the following way:which bails out with