All of lore.kernel.org
 help / color / mirror / Atom feed
From: Christoph Hellwig <hch@lst.de>
To: Helge Deller <deller@gmx.de>
Cc: linux-parisc <linux-parisc@vger.kernel.org>,
	Kyle McMartin <kyle@mcmartin.ca>,
	Roland McGrath <roland@redhat.com>
Subject: Re: [PATCH] compat_sys_ptrace conversions for parisc
Date: Mon, 25 Aug 2008 18:52:31 +0200	[thread overview]
Message-ID: <20080825165231.GA13428@lst.de> (raw)
In-Reply-To: <200808242033.25481.deller@gmx.de>

This should probably get a little review from Rland, I've added him to
the Cc list.  Although I suspect splitting this into at least two
patches for compat_sys_ptrace vs the rest might make sense.

On Sun, Aug 24, 2008 at 08:33:25PM +0200, Helge Deller wrote:
> This patch does the compat_sys_ptrace conversion for parisc.
> In addition it does convert the parisc ptrace code to use the
> architecture-independent ptrace infrastructure instead of own coding.
> 
> Signed-off-by: Helge Deller <deller@gmx.de>
> 
> diff --git a/arch/parisc/include/asm/ptrace.h b/arch/parisc/include/asm/ptrace.h
> index 3e94c5d..afa5333 100644
> --- a/arch/parisc/include/asm/ptrace.h
> +++ b/arch/parisc/include/asm/ptrace.h
> @@ -47,6 +47,16 @@ struct pt_regs {
>  
>  #define task_regs(task) ((struct pt_regs *) ((char *)(task) + TASK_REGS))
>  
> +#define __ARCH_WANT_COMPAT_SYS_PTRACE
> +
> +struct task_struct;
> +#define arch_has_single_step()	1
> +void user_disable_single_step(struct task_struct *task);
> +void user_enable_single_step(struct task_struct *task);
> +
> +#define arch_has_block_step()	1
> +void user_enable_block_step(struct task_struct *task);
> +
>  /* XXX should we use iaoq[1] or iaoq[0] ? */
>  #define user_mode(regs)			(((regs)->iaoq[0] & 3) ? 1 : 0)
>  #define user_space(regs)		(((regs)->iasq[1] != 0) ? 1 : 0)
> diff --git a/arch/parisc/kernel/ptrace.c b/arch/parisc/kernel/ptrace.c
> index 49c6379..90904f9 100644
> --- a/arch/parisc/kernel/ptrace.c
> +++ b/arch/parisc/kernel/ptrace.c
> @@ -4,6 +4,7 @@
>   * Copyright (C) 2000 Hewlett-Packard Co, Linuxcare Inc.
>   * Copyright (C) 2000 Matthew Wilcox <matthew@wil.cx>
>   * Copyright (C) 2000 David Huggins-Daines <dhd@debian.org>
> + * Copyright (C) 2008 Helge Deller <deller@gmx.de>
>   */
>  
>  #include <linux/kernel.h>
> @@ -27,15 +28,149 @@
>  /* PSW bits we allow the debugger to modify */
>  #define USER_PSW_BITS	(PSW_N | PSW_V | PSW_CB)
>  
> -#undef DEBUG_PTRACE
> +/*
> + * Called by kernel/ptrace.c when detaching..
> + *
> + * Make sure single step bits etc are not set.
> + */
> +void ptrace_disable(struct task_struct *task)
> +{
> +	task->ptrace &= ~(PT_SINGLESTEP|PT_BLOCKSTEP);
>  
> -#ifdef DEBUG_PTRACE
> -#define DBG(x...)	printk(x)
> -#else
> -#define DBG(x...)
> -#endif
> +	/* make sure the trap bits are not set */
> +	pa_psw(task)->r = 0;
> +	pa_psw(task)->t = 0;
> +	pa_psw(task)->h = 0;
> +	pa_psw(task)->l = 0;
> +}
> +
> +/*
> + * The following functions are called by ptrace_resume() when
> + * enabling or disabling single/block tracing.
> + */
> +void user_disable_single_step(struct task_struct *task)
> +{
> +	ptrace_disable(task);
> +}
> +
> +void user_enable_single_step(struct task_struct *task)
> +{
> +	task->ptrace &= ~PT_BLOCKSTEP;
> +	task->ptrace |= PT_SINGLESTEP;
> +
> +	if (pa_psw(task)->n) {
> +		struct siginfo si;
> +
> +		/* Nullified, just crank over the queue. */
> +		task_regs(task)->iaoq[0] = task_regs(task)->iaoq[1];
> +		task_regs(task)->iasq[0] = task_regs(task)->iasq[1];
> +		task_regs(task)->iaoq[1] = task_regs(task)->iaoq[0] + 4;
> +		pa_psw(task)->n = 0;
> +		pa_psw(task)->x = 0;
> +		pa_psw(task)->y = 0;
> +		pa_psw(task)->z = 0;
> +		pa_psw(task)->b = 0;
> +		ptrace_disable(task);
> +		/* Don't wake up the task, but let the
> +		   parent know something happened. */
> +		si.si_code = TRAP_TRACE;
> +		si.si_addr = (void __user *) (task_regs(task)->iaoq[0] & ~3);
> +		si.si_signo = SIGTRAP;
> +		si.si_errno = 0;
> +		force_sig_info(SIGTRAP, &si, task);
> +		/* notify_parent(task, SIGCHLD); */
> +		return;
> +	}
> +
> +	/* Enable recovery counter traps.  The recovery counter
> +	 * itself will be set to zero on a task switch.  If the
> +	 * task is suspended on a syscall then the syscall return
> +	 * path will overwrite the recovery counter with a suitable
> +	 * value such that it traps once back in user space.  We
> +	 * disable interrupts in the tasks PSW here also, to avoid
> +	 * interrupts while the recovery counter is decrementing.
> +	 */
> +	pa_psw(task)->r = 1;
> +	pa_psw(task)->t = 0;
> +	pa_psw(task)->h = 0;
> +	pa_psw(task)->l = 0;
> +}
> +
> +void user_enable_block_step(struct task_struct *task)
> +{
> +	task->ptrace &= ~PT_SINGLESTEP;
> +	task->ptrace |= PT_BLOCKSTEP;
> +
> +	/* Enable taken branch trap. */
> +	pa_psw(task)->r = 0;
> +	pa_psw(task)->t = 1;
> +	pa_psw(task)->h = 0;
> +	pa_psw(task)->l = 0;
> +}
> +
> +long arch_ptrace(struct task_struct *child, long request, long addr, long data)
> +{
> +	unsigned long tmp;
> +	long ret = -EIO;
>  
> -#ifdef CONFIG_64BIT
> +	switch (request) {
> +
> +	/* Read the word at location addr in the USER area.  For ptraced
> +	   processes, the kernel saves all regs on a syscall. */
> +	case PTRACE_PEEKUSR:
> +		if ((addr & (sizeof(long)-1)) ||
> +		    (unsigned long) addr >= sizeof(struct pt_regs))
> +			break;
> +		tmp = *(unsigned long *) ((char *) task_regs(child) + addr);
> +		ret = put_user(tmp, (unsigned long *) data);
> +		break;
> +
> +	/* Write the word at location addr in the USER area.  This will need
> +	   to change when the kernel no longer saves all regs on a syscall.
> +	   FIXME.  There is a problem at the moment in that r3-r18 are only
> +	   saved if the process is ptraced on syscall entry, and even then
> +	   those values are overwritten by actual register values on syscall
> +	   exit. */
> +	case PTRACE_POKEUSR:
> +		/* Some register values written here may be ignored in
> +		 * entry.S:syscall_restore_rfi; e.g. iaoq is written with
> +		 * r31/r31+4, and not with the values in pt_regs.
> +		 */
> +		if (addr == PT_PSW) {
> +			/* Allow writing to Nullify, Divide-step-correction,
> +			 * and carry/borrow bits.
> +			 * BEWARE, if you set N, and then single step, it won't
> +			 * stop on the nullified instruction.
> +			 */
> +			data &= USER_PSW_BITS;
> +			task_regs(child)->gr[0] &= ~USER_PSW_BITS;
> +			task_regs(child)->gr[0] |= data;
> +			ret = 0;
> +			break;
> +		}
> +
> +		if ((addr & (sizeof(long)-1)) ||
> +		    (unsigned long) addr >= sizeof(struct pt_regs))
> +			break;
> +		if ((addr >= PT_GR1 && addr <= PT_GR31) ||
> +				addr == PT_IAOQ0 || addr == PT_IAOQ1 ||
> +				(addr >= PT_FR0 && addr <= PT_FR31 + 4) ||
> +				addr == PT_SAR) {
> +			*(unsigned long *) ((char *) task_regs(child) + addr) = data;
> +			ret = 0;
> +		}
> +		break;
> +
> +	default:
> +		ret = ptrace_request(child, request, addr, data);
> +		break;
> +	}
> +
> +	return ret;
> +}
> +
> +
> +#ifdef CONFIG_COMPAT
>  
>  /* This function is needed to translate 32 bit pt_regs offsets in to
>   * 64 bit pt_regs offsets.  For example, a 32 bit gdb under a 64 bit kernel
> @@ -61,106 +196,25 @@ static long translate_usr_offset(long offset)
>  	else
>  		return -1;
>  }
> -#endif
>  
> -/*
> - * Called by kernel/ptrace.c when detaching..
> - *
> - * Make sure single step bits etc are not set.
> - */
> -void ptrace_disable(struct task_struct *child)
> +long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
> +			compat_ulong_t addr, compat_ulong_t data)
>  {
> -	/* make sure the trap bits are not set */
> -	pa_psw(child)->r = 0;
> -	pa_psw(child)->t = 0;
> -	pa_psw(child)->h = 0;
> -	pa_psw(child)->l = 0;
> -}
> -
> -long arch_ptrace(struct task_struct *child, long request, long addr, long data)
> -{
> -	long ret;
> -#ifdef DEBUG_PTRACE
> -	long oaddr=addr, odata=data;
> -#endif
> +	compat_uint_t tmp;
> +	long ret = -EIO;
>  
>  	switch (request) {
> -	case PTRACE_PEEKTEXT: /* read word at location addr. */ 
> -	case PTRACE_PEEKDATA: {
> -#ifdef CONFIG_64BIT
> -		if (__is_compat_task(child)) {
> -			int copied;
> -			unsigned int tmp;
> -
> -			addr &= 0xffffffffL;
> -			copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
> -			ret = -EIO;
> -			if (copied != sizeof(tmp))
> -				goto out_tsk;
> -			ret = put_user(tmp,(unsigned int *) data);
> -			DBG("sys_ptrace(PEEK%s, %d, %lx, %lx) returning %ld, data %x\n",
> -				request == PTRACE_PEEKTEXT ? "TEXT" : "DATA",
> -				pid, oaddr, odata, ret, tmp);
> -		}
> -		else
> -#endif
> -			ret = generic_ptrace_peekdata(child, addr, data);
> -		goto out_tsk;
> -	}
>  
> -	/* when I and D space are separate, this will have to be fixed. */
> -	case PTRACE_POKETEXT: /* write the word at location addr. */
> -	case PTRACE_POKEDATA:
> -		ret = 0;
> -#ifdef CONFIG_64BIT
> -		if (__is_compat_task(child)) {
> -			unsigned int tmp = (unsigned int)data;
> -			DBG("sys_ptrace(POKE%s, %d, %lx, %lx)\n",
> -				request == PTRACE_POKETEXT ? "TEXT" : "DATA",
> -				pid, oaddr, odata);
> -			addr &= 0xffffffffL;
> -			if (access_process_vm(child, addr, &tmp, sizeof(tmp), 1) == sizeof(tmp))
> -				goto out_tsk;
> -		}
> -		else
> -#endif
> -		{
> -			if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
> -				goto out_tsk;
> -		}
> -		ret = -EIO;
> -		goto out_tsk;
> -
> -	/* Read the word at location addr in the USER area.  For ptraced
> -	   processes, the kernel saves all regs on a syscall. */
> -	case PTRACE_PEEKUSR: {
> -		ret = -EIO;
> -#ifdef CONFIG_64BIT
> -		if (__is_compat_task(child)) {
> -			unsigned int tmp;
> -
> -			if (addr & (sizeof(int)-1))
> -				goto out_tsk;
> -			if ((addr = translate_usr_offset(addr)) < 0)
> -				goto out_tsk;
> -
> -			tmp = *(unsigned int *) ((char *) task_regs(child) + addr);
> -			ret = put_user(tmp, (unsigned int *) data);
> -			DBG("sys_ptrace(PEEKUSR, %d, %lx, %lx) returning %ld, addr %lx, data %x\n",
> -				pid, oaddr, odata, ret, addr, tmp);
> -		}
> -		else
> -#endif
> -		{
> -			unsigned long tmp;
> +	case PTRACE_PEEKUSR:
> +		if (addr & (sizeof(compat_uint_t)-1))
> +			break;
> +		addr = translate_usr_offset(addr);
> +		if (addr < 0)
> +			break;
>  
> -			if ((addr & (sizeof(long)-1)) || (unsigned long) addr >= sizeof(struct pt_regs))
> -				goto out_tsk;
> -			tmp = *(unsigned long *) ((char *) task_regs(child) + addr);
> -			ret = put_user(tmp, (unsigned long *) data);
> -		}
> -		goto out_tsk;
> -	}
> +		tmp = *(compat_uint_t *) ((char *) task_regs(child) + addr);
> +		ret = put_user(tmp, (compat_uint_t *) (unsigned long) data);
> +		break;
>  
>  	/* Write the word at location addr in the USER area.  This will need
>  	   to change when the kernel no longer saves all regs on a syscall.
> @@ -169,185 +223,46 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
>  	   those values are overwritten by actual register values on syscall
>  	   exit. */
>  	case PTRACE_POKEUSR:
> -		ret = -EIO;
>  		/* Some register values written here may be ignored in
>  		 * entry.S:syscall_restore_rfi; e.g. iaoq is written with
>  		 * r31/r31+4, and not with the values in pt_regs.
>  		 */
> -		 /* PT_PSW=0, so this is valid for 32 bit processes under 64
> -		 * bit kernels.
> -		 */
>  		if (addr == PT_PSW) {
> -			/* PT_PSW=0, so this is valid for 32 bit processes
> -			 * under 64 bit kernels.
> -			 *
> -			 * Allow writing to Nullify, Divide-step-correction,
> -			 * and carry/borrow bits.
> -			 * BEWARE, if you set N, and then single step, it won't
> -			 * stop on the nullified instruction.
> +			/* Since PT_PSW==0, it is valid for 32 bit processes
> +			 * under 64 bit kernels as well.
>  			 */
> -			DBG("sys_ptrace(POKEUSR, %d, %lx, %lx)\n",
> -				pid, oaddr, odata);
> -			data &= USER_PSW_BITS;
> -			task_regs(child)->gr[0] &= ~USER_PSW_BITS;
> -			task_regs(child)->gr[0] |= data;
> -			ret = 0;
> -			goto out_tsk;
> -		}
> -#ifdef CONFIG_64BIT
> -		if (__is_compat_task(child)) {
> -			if (addr & (sizeof(int)-1))
> -				goto out_tsk;
> -			if ((addr = translate_usr_offset(addr)) < 0)
> -				goto out_tsk;
> -			DBG("sys_ptrace(POKEUSR, %d, %lx, %lx) addr %lx\n",
> -				pid, oaddr, odata, addr);
> +			ret = arch_ptrace(child, request, addr, data);
> +		} else {
> +			if (addr & (sizeof(compat_uint_t)-1))
> +				break;
> +			addr = translate_usr_offset(addr);
> +			if (addr < 0)
> +				break;
>  			if (addr >= PT_FR0 && addr <= PT_FR31 + 4) {
>  				/* Special case, fp regs are 64 bits anyway */
> -				*(unsigned int *) ((char *) task_regs(child) + addr) = data;
> +				*(__u64 *) ((char *) task_regs(child) + addr) = data;
>  				ret = 0;
>  			}
>  			else if ((addr >= PT_GR1+4 && addr <= PT_GR31+4) ||
>  					addr == PT_IAOQ0+4 || addr == PT_IAOQ1+4 ||
>  					addr == PT_SAR+4) {
>  				/* Zero the top 32 bits */
> -				*(unsigned int *) ((char *) task_regs(child) + addr - 4) = 0;
> -				*(unsigned int *) ((char *) task_regs(child) + addr) = data;
> +				*(__u32 *) ((char *) task_regs(child) + addr - 4) = 0;
> +				*(__u32 *) ((char *) task_regs(child) + addr) = data;
>  				ret = 0;
>  			}
> -			goto out_tsk;
>  		}
> -		else
> -#endif
> -		{
> -			if ((addr & (sizeof(long)-1)) || (unsigned long) addr >= sizeof(struct pt_regs))
> -				goto out_tsk;
> -			if ((addr >= PT_GR1 && addr <= PT_GR31) ||
> -					addr == PT_IAOQ0 || addr == PT_IAOQ1 ||
> -					(addr >= PT_FR0 && addr <= PT_FR31 + 4) ||
> -					addr == PT_SAR) {
> -				*(unsigned long *) ((char *) task_regs(child) + addr) = data;
> -				ret = 0;
> -			}
> -			goto out_tsk;
> -		}
> -
> -	case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
> -	case PTRACE_CONT:
> -		ret = -EIO;
> -		DBG("sys_ptrace(%s)\n",
> -			request == PTRACE_SYSCALL ? "SYSCALL" : "CONT");
> -		if (!valid_signal(data))
> -			goto out_tsk;
> -		child->ptrace &= ~(PT_SINGLESTEP|PT_BLOCKSTEP);
> -		if (request == PTRACE_SYSCALL) {
> -			set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
> -		} else {
> -			clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
> -		}		
> -		child->exit_code = data;
> -		goto out_wake_notrap;
> -
> -	case PTRACE_KILL:
> -		/*
> -		 * make the child exit.  Best I can do is send it a
> -		 * sigkill.  perhaps it should be put in the status
> -		 * that it wants to exit.
> -		 */
> -		ret = 0;
> -		DBG("sys_ptrace(KILL)\n");
> -		if (child->exit_state == EXIT_ZOMBIE)	/* already dead */
> -			goto out_tsk;
> -		child->exit_code = SIGKILL;
> -		goto out_wake_notrap;
> -
> -	case PTRACE_SINGLEBLOCK:
> -		DBG("sys_ptrace(SINGLEBLOCK)\n");
> -		ret = -EIO;
> -		if (!valid_signal(data))
> -			goto out_tsk;
> -		clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
> -		child->ptrace &= ~PT_SINGLESTEP;
> -		child->ptrace |= PT_BLOCKSTEP;
> -		child->exit_code = data;
> -
> -		/* Enable taken branch trap. */
> -		pa_psw(child)->r = 0;
> -		pa_psw(child)->t = 1;
> -		pa_psw(child)->h = 0;
> -		pa_psw(child)->l = 0;
> -		goto out_wake;
> -
> -	case PTRACE_SINGLESTEP:
> -		DBG("sys_ptrace(SINGLESTEP)\n");
> -		ret = -EIO;
> -		if (!valid_signal(data))
> -			goto out_tsk;
> -
> -		clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
> -		child->ptrace &= ~PT_BLOCKSTEP;
> -		child->ptrace |= PT_SINGLESTEP;
> -		child->exit_code = data;
> -
> -		if (pa_psw(child)->n) {
> -			struct siginfo si;
> -
> -			/* Nullified, just crank over the queue. */
> -			task_regs(child)->iaoq[0] = task_regs(child)->iaoq[1];
> -			task_regs(child)->iasq[0] = task_regs(child)->iasq[1];
> -			task_regs(child)->iaoq[1] = task_regs(child)->iaoq[0] + 4;
> -			pa_psw(child)->n = 0;
> -			pa_psw(child)->x = 0;
> -			pa_psw(child)->y = 0;
> -			pa_psw(child)->z = 0;
> -			pa_psw(child)->b = 0;
> -			ptrace_disable(child);
> -			/* Don't wake up the child, but let the
> -			   parent know something happened. */
> -			si.si_code = TRAP_TRACE;
> -			si.si_addr = (void __user *) (task_regs(child)->iaoq[0] & ~3);
> -			si.si_signo = SIGTRAP;
> -			si.si_errno = 0;
> -			force_sig_info(SIGTRAP, &si, child);
> -			//notify_parent(child, SIGCHLD);
> -			//ret = 0;
> -			goto out_wake;
> -		}
> -
> -		/* Enable recovery counter traps.  The recovery counter
> -		 * itself will be set to zero on a task switch.  If the
> -		 * task is suspended on a syscall then the syscall return
> -		 * path will overwrite the recovery counter with a suitable
> -		 * value such that it traps once back in user space.  We
> -		 * disable interrupts in the childs PSW here also, to avoid
> -		 * interrupts while the recovery counter is decrementing.
> -		 */
> -		pa_psw(child)->r = 1;
> -		pa_psw(child)->t = 0;
> -		pa_psw(child)->h = 0;
> -		pa_psw(child)->l = 0;
> -		/* give it a chance to run. */
> -		goto out_wake;
> -
> -	case PTRACE_GETEVENTMSG:
> -                ret = put_user(child->ptrace_message, (unsigned int __user *) data);
> -		goto out_tsk;
> +		break;
>  
>  	default:
> -		ret = ptrace_request(child, request, addr, data);
> -		goto out_tsk;
> +		ret = compat_ptrace_request(child, request, addr, data);
> +		break;
>  	}
>  
> -out_wake_notrap:
> -	ptrace_disable(child);
> -out_wake:
> -	wake_up_process(child);
> -	ret = 0;
> -out_tsk:
> -	DBG("arch_ptrace(%ld, %d, %lx, %lx) returning %ld\n",
> -		request, pid, oaddr, odata, ret);
>  	return ret;
>  }
> +#endif
> +
>  
>  void syscall_trace(void)
>  {
> diff --git a/arch/parisc/kernel/syscall_table.S b/arch/parisc/kernel/syscall_table.S
> index 6b5ac38..e719f27 100644
> --- a/arch/parisc/kernel/syscall_table.S
> +++ b/arch/parisc/kernel/syscall_table.S
> @@ -87,7 +87,7 @@
>  	ENTRY_SAME(setuid)
>  	ENTRY_SAME(getuid)
>  	ENTRY_COMP(stime)		/* 25 */
> -	ENTRY_SAME(ptrace)
> +	ENTRY_COMP(ptrace)
>  	ENTRY_SAME(alarm)
>  	/* see stat comment */
>  	ENTRY_COMP(newfstat)
---end quoted text---

  reply	other threads:[~2008-08-25 16:52 UTC|newest]

Thread overview: 21+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-08-24 18:26 [PATCH] - Patch series for parisc Helge Deller
2008-08-24 18:33 ` [PATCH] compat_sys_ptrace conversions " Helge Deller
2008-08-25 16:52   ` Christoph Hellwig [this message]
2008-08-26 21:09     ` Roland McGrath
2008-08-25 17:11   ` Kyle McMartin
2008-08-25 17:49     ` Helge Deller
2008-08-26 20:03       ` Christoph Hellwig
2008-08-24 18:45 ` [PATCH] fix crash when trying to unwind user space Helge Deller
2008-08-24 18:51 ` [PATCH] drop superfluous .align 16 Helge Deller
2008-08-24 18:57   ` James Bottomley
2008-08-25 12:31     ` Helge Deller
2008-08-26  4:26       ` Grant Grundler
2008-08-26 12:42         ` Carlos O'Donell
2008-08-26 14:10           ` James Bottomley
2008-08-26 15:35             ` Carlos O'Donell
2008-08-24 19:04 ` [PATCH] ldcw inline assembler patch Helge Deller
2008-08-24 19:21 ` [PATCH] Change cpu_data[] and cpu_devices[] from array sized by NR_CPUS to per_cpu variables Helge Deller
2008-08-24 21:24   ` Helge Deller
2008-08-27  4:51     ` Grant Grundler
2008-08-27 20:42       ` Helge Deller
2008-08-24 19:49 ` [PATCH] - Patch series for parisc Helge Deller

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20080825165231.GA13428@lst.de \
    --to=hch@lst.de \
    --cc=deller@gmx.de \
    --cc=kyle@mcmartin.ca \
    --cc=linux-parisc@vger.kernel.org \
    --cc=roland@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.