Skip to contentSkip to conversation

kprobes-func-args-268-rc3.patch

PATCH Andi Kleen 2 participants 6 messages Aug 5, 2004 1 message not in the archive

lore
Share & tools
lore

A message that is not in the archive (sent off-list or not yet received): [email protected]

Andi Kleen

author
#1 lore raw
Quoted 7 lines · Prasanna S Panchamukhi

traps again to restore processor state and switch back to the probed function. Linus noted correctly at KS that we need to be careful as gcc assumes that the callee owns arguments. For the time being we try to avoid tailcalls in the probe function; in the long run we should probably also save and restore enough stack bytes to cover argument space.

Quoted 8 lines

Sample Usage:

	static int jip_queue_xmit(struct sk_buff *skb, int ipfragok)
	{
		... whatever ...
		jprobe_return();
		/*No tailcalls please */
		return 0;
	}

I think you misunderstood Linus' suggestion. The problem with modifying arguments on the stack frame is always there because the C ABI allows it. One suggested solution was to use a second function call that passes the arguments again to get a private copy. But the compiler's tail call optimization could sabotate that when you a are not careful.

That's all quite hackish and compiler dependent. I would suggest an assembly wrapper that copies the arguments when !CONFIG_REGPARM. Just assume the function doesn't have more than a fixed number of arguments, that should be good enough.

This way you avoid any subtle compiler dependencies. With CONFIG_REGPARM it's enough to just save/restore pt_regs, which kprobes will do anyways.

Review

Quoted 6 lines

static struct kprobe *current_kprobe;
static unsigned long kprobe_status, kprobe_old_eflags, kprobe_saved_eflags;

(quoted diff) +3 -0
+static struct pt_regs kprobe_saved_regs;
+static long *kprobe_saved_esp;
+extern void show_registers(struct pt_regs *regs);

Shouldn't that be in some header?

Review

Quoted 6 lines
(quoted diff) +6 -0
+
+int longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
+{
+	u8 *addr = (u8 *)(regs->eip-1);
+
+	if ((addr > (u8 *)jprobe_return) && (addr < (u8 *)jprobe_return_end)) {

It would be probably safer to use RELOC_HIDE on the function pointer here, just to be safe against future gcc optimizations

The rest looks ok.

-Andi

#2 lore raw
Quoted 17 lines · Andi Kleen
Quoted 7 lines · Prasanna S Panchamukhi

traps again to restore processor state and switch back to the probed function. Linus noted correctly at KS that we need to be careful as gcc assumes that the callee owns arguments. For the time being we try to avoid tailcalls in the probe function; in the long run we should probably also save and restore enough stack bytes to cover argument space.

Quoted 8 lines

Sample Usage:

	static int jip_queue_xmit(struct sk_buff *skb, int ipfragok)
	{
		... whatever ...
		jprobe_return();
		/*No tailcalls please */
		return 0;
	}
Quoted 3 lines

I think you misunderstood Linus' suggestion. The problem with modifying arguments on the stack frame is always there because the C ABI allows it. One suggested solution was to use a second function

I did realise that it is the ABI which allows this, but I thought that the only situation in which we know gcc to actually clobber arguments from the callee in practice is for tailcall optimization. So I was looking for ways to avoid that ... assuming the way we code the probe function is under our control.

I'm not sure if that can be guaranteed and yes saving bytes from stack would avoid the problem totally (hence the comment) and make it less tied to expected innards of the compiler. The only issue with that is deciding the maximum number of arguments so it is generic enough.

Quoted 4 lines

call that passes the arguments again to get a private copy. But the compiler's tail call optimization could sabotate that when you a are not careful.

Quoted 9 lines

That's all quite hackish and compiler dependent. I would suggest an assembly wrapper that copies the arguments when !CONFIG_REGPARM. Just assume the function doesn't have more than a fixed number of arguments, that should be good enough.

This way you avoid any subtle compiler dependencies. With CONFIG_REGPARM it's enough to just save/restore pt_regs, which kprobes will do anyways.

Quoted 1 line

Even with CONFIG_REGPARM, if you have a large number of arguments for example, is spill over into stack a possibility ?

Regards
Suparna

Signature · 3 lines
Suparna Bhattacharya ([email protected])
Linux Technology Center
IBM Software Lab, India
author
#3 lore raw
Quoted 7 lines · Suparna Bhattacharya
Quoted 3 lines

I think you misunderstood Linus' suggestion. The problem with modifying arguments on the stack frame is always there because the C ABI allows it. One suggested solution was to use a second function

I did realise that it is the ABI which allows this, but I thought that the only situation in which we know gcc to actually clobber arguments from the callee in practice is for tailcall optimization.

It just breaks the most common workaround.

Quoted 5 lines

I'm not sure if that can be guaranteed and yes saving bytes from stack would avoid the problem totally (hence the comment) and make it less tied to expected innards of the compiler. The only issue with that is deciding the maximum number of arguments so it is generic enough.

64bytes, aka 16 arguments seem far enough.

Quoted 9 lines
Quoted 9 lines

call that passes the arguments again to get a private copy. But the compiler's tail call optimization could sabotate that when you a are not careful.

That's all quite hackish and compiler dependent. I would suggest an assembly wrapper that copies the arguments when !CONFIG_REGPARM. Just assume the function doesn't have more than a fixed number of arguments, that should be good enough.

Quoted 8 lines
Quoted 4 lines

This way you avoid any subtle compiler dependencies. With CONFIG_REGPARM it's enough to just save/restore pt_regs, which kprobes will do anyways.

Quoted 1 line

Even with CONFIG_REGPARM, if you have a large number of arguments for example, is spill over into stack a possibility ?

Yes. For more than three (Linux uses -mregparm=3) Also varargs arguments will be always on the stack I think.

-Andi

#4 lore raw
Quoted 10 lines · Andi Kleen
Quoted 7 lines · Suparna Bhattacharya
Quoted 3 lines

I think you misunderstood Linus' suggestion. The problem with modifying arguments on the stack frame is always there because the C ABI allows it. One suggested solution was to use a second function

I did realise that it is the ABI which allows this, but I thought that the only situation in which we know gcc to actually clobber arguments from the callee in practice is for tailcall optimization.

It just breaks the most common workaround.

Just curious, do you know if other cases/optimizations where the callee clobbers arguments on stack ?

Quoted 8 lines
Quoted 6 lines

I'm not sure if that can be guaranteed and yes saving bytes from stack would avoid the problem totally (hence the comment) and make it less tied to expected innards of the compiler. The only issue with that is deciding the maximum number of arguments so it is generic enough.

64bytes, aka 16 arguments seem far enough.

OK, is there is consensus on this ?
We'd have to make the code check for stack boundary etc and probably compare and copy back only if there has been a change.

Quoted 15 lines
Quoted 15 lines
Quoted 14 lines

call that passes the arguments again to get a private copy. But the compiler's tail call optimization could sabotate that when you a are not careful.

That's all quite hackish and compiler dependent. I would suggest an assembly wrapper that copies the arguments when !CONFIG_REGPARM. Just assume the function doesn't have more than a fixed number of arguments, that should be good enough.

This way you avoid any subtle compiler dependencies. With CONFIG_REGPARM it's enough to just save/restore pt_regs, which kprobes will do anyways.

Quoted 1 line
Quoted 6 lines
Quoted 3 lines

Even with CONFIG_REGPARM, if you have a large number of arguments for example, is spill over into stack a possibility ?

Yes. For more than three (Linux uses -mregparm=3) Also varargs arguments will be always on the stack I think.

Right, so making the copy dependent on !CONFIG_REGPARM wouldn't make sense would it ?

Regards
Suparna

Signature · 3 lines
Suparna Bhattacharya ([email protected])
Linux Technology Center
IBM Software Lab, India
author
#5 lore raw
Quoted 6 lines · Suparna Bhattacharya
Quoted 5 lines · Andi Kleen
Quoted 4 lines · Suparna Bhattacharya
Quoted 3 lines

I think you misunderstood Linus' suggestion. The problem with modifying arguments on the stack frame is always there because the C ABI allows it. One suggested solution was to use a second function

Quoted 8 lines
Quoted 5 lines
Quoted 3 lines

I did realise that it is the ABI which allows this, but I thought that the only situation in which we know gcc to actually clobber arguments from the callee in practice is for tailcall optimization.

It just breaks the most common workaround.

Just curious, do you know if other cases/optimizations where the callee clobbers arguments on stack ?

gcc can do it all the time. tail call is just a special case.

It happens relatively rarely because often it caches the data in registers. But when there is enough register pressure it can be written back to the original argument slot.

If you pass a structure by value it happens more often (at least in older gccs, 3.5 now loads this into registers too)

On -O0 code I would also expect it to happen often.

Quoted 11 lines
Quoted 9 lines
Quoted 7 lines

I'm not sure if that can be guaranteed and yes saving bytes from stack would avoid the problem totally (hence the comment) and make it less tied to expected innards of the compiler. The only issue with that is deciding the maximum number of arguments so it is generic enough.

64bytes, aka 16 arguments seem far enough.

OK, is there is consensus on this ?

I think there is a clear consensus that anybody who uses 16 arguments in a kernel function already did something very wrong.

Passing structures by value may be reasonable, but not supporting that for big structures is a reasonable restriction.

Quoted 2 lines

We'd have to make the code check for stack boundary etc and probably compare and copy back only if there has been a change.

Why? And what stack boundary?

The probe is not supposed to modify the arguments, isn't it, so I don't see why you ever want to copy back.

I would write the trampoline in assembly btw, doing such things in C is usually very fragile.

Quoted 11 lines
Quoted 8 lines
Quoted 5 lines
Quoted 1 line
Quoted 1 line

Even with CONFIG_REGPARM, if you have a large number of arguments for example, is spill over into stack a possibility ?

Yes. For more than three (Linux uses -mregparm=3) Also varargs arguments will be always on the stack I think.

Right, so making the copy dependent on !CONFIG_REGPARM wouldn't make sense would it ?

Yes, it wouldn't.

-Andi

#6 lore raw
Quoted 48 lines · Andi Kleen
Quoted 6 lines · Suparna Bhattacharya
Quoted 5 lines · Andi Kleen
Quoted 4 lines · Suparna Bhattacharya
Quoted 3 lines

I think you misunderstood Linus' suggestion. The problem with modifying arguments on the stack frame is always there because the C ABI allows it. One suggested solution was to use a second function

Quoted 8 lines
Quoted 5 lines
Quoted 3 lines

I did realise that it is the ABI which allows this, but I thought that the only situation in which we know gcc to actually clobber arguments from the callee in practice is for tailcall optimization.

It just breaks the most common workaround.

Just curious, do you know if other cases/optimizations where the callee clobbers arguments on stack ?

gcc can do it all the time. tail call is just a special case.

It happens relatively rarely because often it caches the data in registers. But when there is enough register pressure it can be written back to the original argument slot.

If you pass a structure by value it happens more often (at least in older gccs, 3.5 now loads this into registers too)

On -O0 code I would also expect it to happen often.

Quoted 11 lines
Quoted 9 lines
Quoted 7 lines

I'm not sure if that can be guaranteed and yes saving bytes from stack would avoid the problem totally (hence the comment) and make it less tied to expected innards of the compiler. The only issue with that is deciding the maximum number of arguments so it is generic enough.

64bytes, aka 16 arguments seem far enough.

OK, is there is consensus on this ?

I think there is a clear consensus that anybody who uses 16 arguments in a kernel function already did something very wrong.

Passing structures by value may be reasonable, but not supporting that for big structures is a reasonable restriction.

Quoted 2 lines

We'd have to make the code check for stack boundary etc and probably compare and copy back only if there has been a change.

Quoted 7 lines

Why? And what stack boundary?

The probe is not supposed to modify the arguments, isn't it, so I don't see why you ever want to copy back.

I would write the trampoline in assembly btw, doing such things in C is usually very fragile.

Oh, I guess you are suggesting actually copying args forward on stack before passing control to the probe routine. Hence the assembly trampoline.

What I had in mind originally was a little different - i.e. just make the kprobes breakpoint handler itself save the additional 64 KB from stack the way it does for pt_regs right now, before iret ing into the jprobe handler function. And verify and restore that only if needed on the way back (i.e. second trap).

Regards
Suparna

Quoted 16 lines
Quoted 7 lines
Quoted 7 lines
Quoted 6 lines
Quoted 2 lines
Quoted 2 lines

Even with CONFIG_REGPARM, if you have a large number of arguments for example, is spill over into stack a possibility ?

Quoted 5 lines
Quoted 2 lines

Yes. For more than three (Linux uses -mregparm=3) Also varargs arguments will be always on the stack I think.

Right, so making the copy dependent on !CONFIG_REGPARM wouldn't make sense would it ?

Yes, it wouldn't.

-Andi

Signature · 3 lines
Suparna Bhattacharya ([email protected])
Linux Technology Center
IBM Software Lab, India