2 * Copyright (c) 1991, 1992 Paul Kranenburg <pk@cs.few.eur.nl>
3 * Copyright (c) 1993 Branko Lankester <branko@hacktic.nl>
4 * Copyright (c) 1993, 1994, 1995, 1996 Rick Sladkey <jrs@world.std.com>
5 * Copyright (c) 1996-1999 Wichert Akkerman <wichert@cistron.nl>
6 * Copyright (c) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
7 * Linux for s390 port by D.J. Barrow
8 * <barrow_dj@mail.yahoo.com,djbarrow@de.ibm.com>
9 * Copyright (c) 1999-2018 The strace developers.
10 * All rights reserved.
12 * SPDX-License-Identifier: LGPL-2.1-or-later
21 static bool process_vm_readv_not_supported;
23 #ifndef HAVE_PROCESS_VM_READV
25 * Need to do this since process_vm_readv() is not yet available in libc.
26 * When libc is updated, only "static bool process_vm_readv_not_supported"
28 * The name is different to avoid potential collision with OS headers.
30 static ssize_t strace_process_vm_readv(pid_t pid,
31 const struct iovec *lvec,
32 unsigned long liovcnt,
33 const struct iovec *rvec,
34 unsigned long riovcnt,
37 return syscall(__NR_process_vm_readv,
38 (long) pid, lvec, liovcnt, rvec, riovcnt, flags);
40 # define process_vm_readv strace_process_vm_readv
41 #endif /* !HAVE_PROCESS_VM_READV */
44 vm_read_mem(const pid_t pid, void *const laddr,
45 const kernel_ulong_t raddr, const size_t len)
47 const unsigned long truncated_raddr = raddr;
49 #if SIZEOF_LONG < SIZEOF_KERNEL_LONG_T
50 if (raddr != (kernel_ulong_t) truncated_raddr) {
56 const struct iovec local = {
60 const struct iovec remote = {
61 .iov_base = (void *) truncated_raddr,
65 const ssize_t rc = process_vm_readv(pid, &local, 1, &remote, 1, 0);
66 if (rc < 0 && errno == ENOSYS)
67 process_vm_readv_not_supported = true;
73 tracee_addr_is_invalid(kernel_ulong_t addr)
76 #if ANY_WORDSIZE_LESS_THAN_KERNEL_LONG
77 current_wordsize < sizeof(addr) && addr & ~(kernel_ulong_t) -1U;
83 /* legacy method of copying from tracee */
85 umoven_peekdata(const int pid, kernel_ulong_t addr, unsigned int len,
88 unsigned int nread = 0;
89 unsigned int residue = addr & (sizeof(long) - 1);
92 addr &= -sizeof(long); /* aligned address */
98 } u = { .val = ptrace(PTRACE_PEEKDATA, pid, addr, 0) };
103 case ESRCH: case EINVAL:
104 /* these could be seen if the process is gone */
106 case EFAULT: case EIO: case EPERM:
107 /* address space is inaccessible */
109 perror_func_msg("short read (%u < %u)"
116 /* all the rest is strange and should be reported */
117 perror_func_msg("pid:%d @0x%" PRI_klx,
122 unsigned int m = MIN(sizeof(long) - residue, len);
123 memcpy(laddr, &u.x[residue], m);
125 addr += sizeof(long);
135 * Copy `len' bytes of data from process `pid'
136 * at address `addr' to our space at `our_addr'.
139 umoven(struct tcb *const tcp, kernel_ulong_t addr, unsigned int len,
140 void *const our_addr)
142 if (tracee_addr_is_invalid(addr))
145 const int pid = tcp->pid;
147 if (process_vm_readv_not_supported)
148 return umoven_peekdata(pid, addr, len, our_addr);
150 int r = vm_read_mem(pid, our_addr, addr, len);
151 if ((unsigned int) r == len)
154 error_func_msg("short read (%u < %u) @0x%" PRI_klx,
155 (unsigned int) r, len, addr);
161 /* try PTRACE_PEEKDATA */
162 return umoven_peekdata(pid, addr, len, our_addr);
164 /* the process is gone */
166 case EFAULT: case EIO:
167 /* address space is inaccessible */
170 /* all the rest is strange and should be reported */
171 perror_func_msg("pid:%d @0x%" PRI_klx, pid, addr);
177 * Like umoven_peekdata but make the additional effort of looking
178 * for a terminating zero byte.
181 umovestr_peekdata(const int pid, kernel_ulong_t addr, unsigned int len,
184 unsigned int nread = 0;
185 unsigned int residue = addr & (sizeof(long) - 1);
186 void *const orig_addr = laddr;
189 addr &= -sizeof(long); /* aligned address */
194 char x[sizeof(long)];
195 } u = { .val = ptrace(PTRACE_PEEKDATA, pid, addr, 0) };
200 case ESRCH: case EINVAL:
201 /* these could be seen if the process is gone */
203 case EFAULT: case EIO: case EPERM:
204 /* address space is inaccessible */
206 perror_func_msg("short read (%d < %d)"
213 /* all the rest is strange and should be reported */
214 perror_func_msg("pid:%d @0x%" PRI_klx,
219 unsigned int m = MIN(sizeof(long) - residue, len);
220 memcpy(laddr, &u.x[residue], m);
221 while (residue < sizeof(long))
222 if (u.x[residue++] == '\0')
223 return (laddr - orig_addr) + residue;
225 addr += sizeof(long);
235 * Like `umove' but make the additional effort of looking
236 * for a terminating zero byte.
238 * Returns < 0 on error, strlen + 1 if NUL was seen,
239 * else 0 if len bytes were read but no NUL byte seen.
241 * Note: there is no guarantee we won't overwrite some bytes
242 * in laddr[] _after_ terminating NUL (but, of course,
243 * we never write past laddr[len-1]).
246 umovestr(struct tcb *const tcp, kernel_ulong_t addr, unsigned int len,
249 if (tracee_addr_is_invalid(addr))
252 const int pid = tcp->pid;
254 if (process_vm_readv_not_supported)
255 return umovestr_peekdata(pid, addr, len, laddr);
257 const size_t page_size = get_pagesize();
258 const size_t page_mask = page_size - 1;
259 unsigned int nread = 0;
263 * Don't cross pages, otherwise we can get EFAULT
264 * and fail to notice that terminating NUL lies
265 * in the existing (first) page.
267 unsigned int chunk_len = len > page_size ? page_size : len;
268 unsigned int end_in_page = (addr + chunk_len) & page_mask;
269 if (chunk_len > end_in_page) /* crosses to the next page */
270 chunk_len -= end_in_page;
272 int r = vm_read_mem(pid, laddr, addr, chunk_len);
274 char *nul_addr = memchr(laddr, '\0', r);
277 return (nul_addr - laddr) + 1;
287 /* try PTRACE_PEEKDATA */
289 return umovestr_peekdata(pid, addr,
291 ATTRIBUTE_FALLTHROUGH;
292 case EFAULT: case EIO:
293 /* address space is inaccessible */
295 perror_func_msg("short read (%d < %d)"
301 /* the process is gone */
304 /* all the rest is strange and should be reported */
305 perror_func_msg("pid:%d @0x%" PRI_klx, pid, addr);