Coverage Report

Created: 2025-07-11 06:46

/src/elfutils/libdwfl/linux-pid-attach.c
Line
Count
Source (jump to first uncovered line)
1
/* Get Dwarf Frame state for target live PID process.
2
   Copyright (C) 2013, 2014, 2015, 2018, 2025 Red Hat, Inc.
3
   This file is part of elfutils.
4
5
   This file is free software; you can redistribute it and/or modify
6
   it under the terms of either
7
8
     * the GNU Lesser General Public License as published by the Free
9
       Software Foundation; either version 3 of the License, or (at
10
       your option) any later version
11
12
   or
13
14
     * the GNU General Public License as published by the Free
15
       Software Foundation; either version 2 of the License, or (at
16
       your option) any later version
17
18
   or both in parallel, as here.
19
20
   elfutils is distributed in the hope that it will be useful, but
21
   WITHOUT ANY WARRANTY; without even the implied warranty of
22
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
23
   General Public License for more details.
24
25
   You should have received copies of the GNU General Public License and
26
   the GNU Lesser General Public License along with this program.  If
27
   not, see <http://www.gnu.org/licenses/>.  */
28
29
#ifdef HAVE_CONFIG_H
30
# include <config.h>
31
#endif
32
33
#include <system.h>
34
35
#include "libelfP.h"
36
#include "libdwflP.h"
37
#include <sys/types.h>
38
#include <sys/stat.h>
39
#include <fcntl.h>
40
#include <dirent.h>
41
42
#ifdef __linux__
43
44
#include <sys/uio.h>
45
#include <sys/ptrace.h>
46
#include <sys/syscall.h>
47
#include <sys/wait.h>
48
49
static bool
50
linux_proc_pid_is_stopped (pid_t pid)
51
0
{
52
0
  char buffer[64];
53
0
  FILE *procfile;
54
0
  bool retval, have_state;
55
56
0
  snprintf (buffer, sizeof (buffer), "/proc/%ld/status", (long) pid);
57
0
  procfile = fopen (buffer, "r");
58
0
  if (procfile == NULL)
59
0
    return false;
60
61
0
  have_state = false;
62
0
  while (fgets (buffer, sizeof (buffer), procfile) != NULL)
63
0
    if (startswith (buffer, "State:"))
64
0
      {
65
0
  have_state = true;
66
0
  break;
67
0
      }
68
0
  retval = (have_state && strstr (buffer, "T (stopped)") != NULL);
69
0
  fclose (procfile);
70
0
  return retval;
71
0
}
72
73
bool
74
internal_function
75
__libdwfl_ptrace_attach (pid_t tid, bool *tid_was_stoppedp)
76
0
{
77
0
  if (ptrace (PTRACE_ATTACH, tid, NULL, NULL) != 0)
78
0
    {
79
0
      __libdwfl_seterrno (DWFL_E_ERRNO);
80
0
      return false;
81
0
    }
82
0
  *tid_was_stoppedp = linux_proc_pid_is_stopped (tid);
83
0
  if (*tid_was_stoppedp)
84
0
    {
85
      /* Make sure there is a SIGSTOP signal pending even when the process is
86
   already State: T (stopped).  Older kernels might fail to generate
87
   a SIGSTOP notification in that case in response to our PTRACE_ATTACH
88
   above.  Which would make the waitpid below wait forever.  So emulate
89
   it.  Since there can only be one SIGSTOP notification pending this is
90
   safe.  See also gdb/linux-nat.c linux_nat_post_attach_wait.  */
91
0
      syscall (__NR_tkill, tid, SIGSTOP);
92
0
      ptrace (PTRACE_CONT, tid, NULL, NULL);
93
0
    }
94
0
  for (;;)
95
0
    {
96
0
      int status;
97
0
      if (waitpid (tid, &status, __WALL) != tid || !WIFSTOPPED (status))
98
0
  {
99
0
    int saved_errno = errno;
100
0
    ptrace (PTRACE_DETACH, tid, NULL, NULL);
101
0
    errno = saved_errno;
102
0
    __libdwfl_seterrno (DWFL_E_ERRNO);
103
0
    return false;
104
0
  }
105
0
      if (WSTOPSIG (status) == SIGSTOP)
106
0
  break;
107
0
      if (ptrace (PTRACE_CONT, tid, NULL,
108
0
      (void *) (uintptr_t) WSTOPSIG (status)) != 0)
109
0
  {
110
0
    int saved_errno = errno;
111
0
    ptrace (PTRACE_DETACH, tid, NULL, NULL);
112
0
    errno = saved_errno;
113
0
    __libdwfl_seterrno (DWFL_E_ERRNO);
114
0
    return false;
115
0
  }
116
0
    }
117
0
  return true;
118
0
}
119
120
#ifdef HAVE_PROCESS_VM_READV
121
/* Note that the result word size depends on the architecture word size.
122
   That is sizeof long. */
123
static bool
124
read_cached_memory (struct __libdwfl_pid_arg *pid_arg,
125
        Dwarf_Addr addr, Dwarf_Word *result)
126
0
{
127
  /* Let the ptrace fallback deal with the corner case of the address
128
     possibly crossing a page boundary.  */
129
0
  if ((addr & ((Dwarf_Addr)__LIBDWFL_REMOTE_MEM_CACHE_SIZE - 1))
130
0
      > (Dwarf_Addr)__LIBDWFL_REMOTE_MEM_CACHE_SIZE - sizeof (unsigned long))
131
0
    return false;
132
133
0
  struct __libdwfl_remote_mem_cache *mem_cache = pid_arg->mem_cache;
134
0
  if (mem_cache == NULL)
135
0
    {
136
0
      size_t mem_cache_size = sizeof (struct __libdwfl_remote_mem_cache);
137
0
      mem_cache = malloc (mem_cache_size);
138
0
      if (mem_cache == NULL)
139
0
  return false;
140
141
0
      mem_cache->addr = 0;
142
0
      mem_cache->len = 0;
143
0
      pid_arg->mem_cache = mem_cache;
144
0
    }
145
146
0
  unsigned char *d;
147
0
  if (addr >= mem_cache->addr && addr - mem_cache->addr < mem_cache->len)
148
0
    {
149
0
      d = &mem_cache->buf[addr - mem_cache->addr];
150
0
      if ((((uintptr_t) d) & (sizeof (unsigned long) - 1)) == 0)
151
0
  *result = *(unsigned long *) d;
152
0
      else
153
0
  memcpy (result, d, sizeof (unsigned long));
154
0
      return true;
155
0
    }
156
157
0
  struct iovec local, remote;
158
0
  mem_cache->addr = addr & ~((Dwarf_Addr)__LIBDWFL_REMOTE_MEM_CACHE_SIZE - 1);
159
0
  local.iov_base = mem_cache->buf;
160
0
  local.iov_len = __LIBDWFL_REMOTE_MEM_CACHE_SIZE;
161
0
  remote.iov_base = (void *) (uintptr_t) mem_cache->addr;
162
0
  remote.iov_len = __LIBDWFL_REMOTE_MEM_CACHE_SIZE;
163
164
0
  ssize_t res = process_vm_readv (pid_arg->tid_attached,
165
0
          &local, 1, &remote, 1, 0);
166
0
  if (res != __LIBDWFL_REMOTE_MEM_CACHE_SIZE)
167
0
    {
168
0
      mem_cache->len = 0;
169
0
      return false;
170
0
    }
171
172
0
  mem_cache->len = res;
173
0
  d = &mem_cache->buf[addr - mem_cache->addr];
174
0
  if ((((uintptr_t) d) & (sizeof (unsigned long) - 1)) == 0)
175
0
    *result = *(unsigned long *) d;
176
0
  else
177
0
    memcpy (result, d, sizeof (unsigned long));
178
0
  return true;
179
0
}
180
#endif /* HAVE_PROCESS_VM_READV */
181
182
static void
183
clear_cached_memory (struct __libdwfl_pid_arg *pid_arg)
184
0
{
185
0
  struct __libdwfl_remote_mem_cache *mem_cache = pid_arg->mem_cache;
186
0
  if (mem_cache != NULL)
187
0
    mem_cache->len = 0;
188
0
}
189
190
/* Note that the result word size depends on the architecture word size.
191
   That is sizeof long. */
192
static bool
193
pid_memory_read (Dwfl *dwfl, Dwarf_Addr addr, Dwarf_Word *result, void *arg)
194
0
{
195
0
  struct __libdwfl_pid_arg *pid_arg = arg;
196
0
  pid_t tid = pid_arg->tid_attached;
197
0
  Dwfl_Process *process = dwfl->process;
198
0
  assert (tid > 0);
199
200
0
#ifdef HAVE_PROCESS_VM_READV
201
0
  if (read_cached_memory (pid_arg, addr, result))
202
0
    {
203
0
#if SIZEOF_LONG == 8
204
# if BYTE_ORDER == BIG_ENDIAN
205
      if (ebl_get_elfclass (process->ebl) == ELFCLASS32)
206
  *result >>= 32;
207
# endif
208
0
#endif
209
0
    return true;
210
0
    }
211
0
#endif
212
213
0
  if (ebl_get_elfclass (process->ebl) == ELFCLASS64)
214
0
    {
215
0
#if SIZEOF_LONG == 8
216
0
      errno = 0;
217
0
      *result = ptrace (PTRACE_PEEKDATA, tid, (void *) (uintptr_t) addr, NULL);
218
0
      return errno == 0;
219
#else /* SIZEOF_LONG != 8 */
220
      /* This should not happen.  */
221
      return false;
222
#endif /* SIZEOF_LONG != 8 */
223
0
    }
224
0
#if SIZEOF_LONG == 8
225
  /* We do not care about reads unaliged to 4 bytes boundary.
226
     But 0x...ffc read of 8 bytes could overrun a page.  */
227
0
  bool lowered = (addr & 4) != 0;
228
0
  if (lowered)
229
0
    addr -= 4;
230
0
#endif /* SIZEOF_LONG == 8 */
231
0
  errno = 0;
232
0
  *result = ptrace (PTRACE_PEEKDATA, tid, (void *) (uintptr_t) addr, NULL);
233
0
  if (errno != 0)
234
0
    return false;
235
0
#if SIZEOF_LONG == 8
236
# if BYTE_ORDER == BIG_ENDIAN
237
  if (! lowered)
238
    *result >>= 32;
239
# else
240
0
  if (lowered)
241
0
    *result >>= 32;
242
0
# endif
243
0
#endif /* SIZEOF_LONG == 8 */
244
0
  *result &= 0xffffffff;
245
0
  return true;
246
0
}
247
248
static pid_t
249
pid_next_thread (Dwfl *dwfl __attribute__ ((unused)), void *dwfl_arg,
250
     void **thread_argp)
251
0
{
252
0
  struct __libdwfl_pid_arg *pid_arg = dwfl_arg;
253
0
  struct dirent *dirent;
254
  /* Start fresh on first traversal. */
255
0
  if (*thread_argp == NULL)
256
0
    rewinddir (pid_arg->dir);
257
0
  do
258
0
    {
259
0
      errno = 0;
260
0
      dirent = readdir (pid_arg->dir);
261
0
      if (dirent == NULL)
262
0
  {
263
0
    if (errno != 0)
264
0
      {
265
0
        __libdwfl_seterrno (DWFL_E_ERRNO);
266
0
        return -1;
267
0
      }
268
0
    return 0;
269
0
  }
270
0
    }
271
0
  while (strcmp (dirent->d_name, ".") == 0
272
0
   || strcmp (dirent->d_name, "..") == 0);
273
0
  char *end;
274
0
  errno = 0;
275
0
  long tidl = strtol (dirent->d_name, &end, 10);
276
0
  if (errno != 0)
277
0
    {
278
0
      __libdwfl_seterrno (DWFL_E_ERRNO);
279
0
      return -1;
280
0
    }
281
0
  pid_t tid = tidl;
282
0
  if (tidl <= 0 || (end && *end) || tid != tidl)
283
0
    {
284
0
      __libdwfl_seterrno (DWFL_E_PARSE_PROC);
285
0
      return -1;
286
0
    }
287
0
  *thread_argp = dwfl_arg;
288
0
  return tid;
289
0
}
290
291
/* Just checks that the thread id exists.  */
292
static bool
293
pid_getthread (Dwfl *dwfl __attribute__ ((unused)), pid_t tid,
294
         void *dwfl_arg, void **thread_argp)
295
0
{
296
0
  *thread_argp = dwfl_arg;
297
0
  if (kill (tid, 0) < 0)
298
0
    {
299
0
      __libdwfl_seterrno (DWFL_E_ERRNO);
300
0
      return false;
301
0
    }
302
0
  return true;
303
0
}
304
305
/* Implement the ebl_set_initial_registers_tid setfunc callback.  */
306
307
bool
308
/* XXX No internal_function annotation,
309
   as this function gets passed as ebl_tid_registers_t *.  */
310
__libdwfl_set_initial_registers_thread (int firstreg, unsigned nregs,
311
           const Dwarf_Word *regs, void *arg)
312
0
{
313
0
  Dwfl_Thread *thread = (Dwfl_Thread *) arg;
314
0
  if (firstreg == -1)
315
0
    {
316
0
      assert (nregs == 1);
317
0
      INTUSE(dwfl_thread_state_register_pc) (thread, *regs);
318
0
      return true;
319
0
    }
320
0
  else if (firstreg == -2)
321
0
    {
322
0
      assert (nregs == 1);
323
0
      INTUSE(dwfl_thread_state_registers) (thread, firstreg, nregs, regs);
324
0
      return true;
325
0
     }
326
0
  assert (nregs > 0);
327
0
  return INTUSE(dwfl_thread_state_registers) (thread, firstreg, nregs, regs);
328
0
}
329
330
static bool
331
pid_set_initial_registers (Dwfl_Thread *thread, void *thread_arg)
332
0
{
333
0
  struct __libdwfl_pid_arg *pid_arg = thread_arg;
334
0
  assert (pid_arg->tid_attached == 0);
335
0
  pid_t tid = INTUSE(dwfl_thread_tid) (thread);
336
0
  if (! pid_arg->assume_ptrace_stopped
337
0
      && ! __libdwfl_ptrace_attach (tid, &pid_arg->tid_was_stopped))
338
0
    return false;
339
0
  pid_arg->tid_attached = tid;
340
0
  Dwfl_Process *process = thread->process;
341
0
  Ebl *ebl = process->ebl;
342
0
  return ebl_set_initial_registers_tid (ebl, tid,
343
0
          __libdwfl_set_initial_registers_thread, thread);
344
0
}
345
346
static void
347
pid_detach (Dwfl *dwfl __attribute__ ((unused)), void *dwfl_arg)
348
0
{
349
0
  struct __libdwfl_pid_arg *pid_arg = dwfl_arg;
350
0
  elf_end (pid_arg->elf);
351
0
  free (pid_arg->mem_cache);
352
0
  close (pid_arg->elf_fd);
353
0
  closedir (pid_arg->dir);
354
0
  free (pid_arg);
355
0
}
356
357
void
358
internal_function
359
__libdwfl_ptrace_detach (pid_t tid, bool tid_was_stopped)
360
0
{
361
  /* This handling is needed only on older Linux kernels such as
362
     2.6.32-358.23.2.el6.ppc64.  Later kernels such as
363
     3.11.7-200.fc19.x86_64 remember the T (stopped) state
364
     themselves and no longer need to pass SIGSTOP during
365
     PTRACE_DETACH.  */
366
0
  ptrace (PTRACE_DETACH, tid, NULL,
367
0
    (void *) (intptr_t) (tid_was_stopped ? SIGSTOP : 0));
368
0
}
369
370
static void
371
pid_thread_detach (Dwfl_Thread *thread, void *thread_arg)
372
0
{
373
0
  struct __libdwfl_pid_arg *pid_arg = thread_arg;
374
0
  pid_t tid = INTUSE(dwfl_thread_tid) (thread);
375
0
  assert (pid_arg->tid_attached == tid);
376
0
  pid_arg->tid_attached = 0;
377
0
  clear_cached_memory (pid_arg);
378
0
  if (! pid_arg->assume_ptrace_stopped)
379
0
    __libdwfl_ptrace_detach (tid, pid_arg->tid_was_stopped);
380
0
}
381
382
static const Dwfl_Thread_Callbacks pid_thread_callbacks =
383
{
384
  pid_next_thread,
385
  pid_getthread,
386
  pid_memory_read,
387
  pid_set_initial_registers,
388
  pid_detach,
389
  pid_thread_detach,
390
};
391
392
int
393
dwfl_linux_proc_attach (Dwfl *dwfl, pid_t pid, bool assume_ptrace_stopped)
394
0
{
395
0
  char buffer[36];
396
0
  FILE *procfile;
397
0
  int err = 0; /* The errno to return and set for dwfl->attcherr.  */
398
399
  /* Make sure to report the actual PID (thread group leader) to
400
     dwfl_attach_state.  */
401
0
  snprintf (buffer, sizeof (buffer), "/proc/%ld/status", (long) pid);
402
0
  procfile = fopen (buffer, "r");
403
0
  if (procfile == NULL)
404
0
    {
405
0
      err = errno;
406
0
    fail:
407
0
      if (dwfl->process == NULL && dwfl->attacherr == DWFL_E_NOERROR)
408
0
  {
409
0
    errno = err;
410
0
    dwfl->attacherr = __libdwfl_canon_error (DWFL_E_ERRNO);
411
0
  }
412
0
      return err;
413
0
    }
414
415
0
  char *line = NULL;
416
0
  size_t linelen = 0;
417
0
  while (getline (&line, &linelen, procfile) >= 0)
418
0
    if (startswith (line, "Tgid:"))
419
0
      {
420
0
  errno = 0;
421
0
  char *endptr;
422
0
  long val = strtol (&line[5], &endptr, 10);
423
0
  if ((errno == ERANGE && val == LONG_MAX)
424
0
      || *endptr != '\n' || val < 0 || val != (pid_t) val)
425
0
    pid = 0;
426
0
  else
427
0
    pid = (pid_t) val;
428
0
  break;
429
0
      }
430
0
  free (line);
431
0
  fclose (procfile);
432
433
0
  if (pid == 0)
434
0
    {
435
0
      err = ESRCH;
436
0
      goto fail;
437
0
    }
438
439
0
  char name[64];
440
0
  int i = snprintf (name, sizeof (name), "/proc/%ld/task", (long) pid);
441
0
  if (i <= 0 || i >= (ssize_t) sizeof (name) - 1)
442
0
    {
443
0
      errno = -ENOMEM;
444
0
      goto fail;
445
0
    }
446
0
  DIR *dir = opendir (name);
447
0
  if (dir == NULL)
448
0
    {
449
0
      err = errno;
450
0
      goto fail;
451
0
    }
452
453
0
  Elf *elf;
454
0
  i = snprintf (name, sizeof (name), "/proc/%ld/exe", (long) pid);
455
0
  assert (i > 0 && i < (ssize_t) sizeof (name) - 1);
456
0
  int elf_fd = open (name, O_RDONLY);
457
0
  if (elf_fd >= 0)
458
0
    {
459
0
      elf = elf_begin (elf_fd, ELF_C_READ_MMAP, NULL);
460
0
      if (elf == NULL)
461
0
  {
462
    /* Just ignore, dwfl_attach_state will fall back to trying
463
       to associate the Dwfl with one of the existing DWfl_Module
464
       ELF images (to know the machine/class backend to use).  */
465
0
    close (elf_fd);
466
0
    elf_fd = -1;
467
0
  }
468
0
    }
469
0
  else
470
0
    elf = NULL;
471
0
  struct __libdwfl_pid_arg *pid_arg = malloc (sizeof *pid_arg);
472
0
  if (pid_arg == NULL)
473
0
    {
474
0
      elf_end (elf);
475
0
      close (elf_fd);
476
0
      closedir (dir);
477
0
      err = ENOMEM;
478
0
      goto fail;
479
0
    }
480
0
  pid_arg->dir = dir;
481
0
  pid_arg->elf = elf;
482
0
  pid_arg->elf_fd = elf_fd;
483
0
  pid_arg->mem_cache = NULL;
484
0
  pid_arg->tid_attached = 0;
485
0
  pid_arg->assume_ptrace_stopped = assume_ptrace_stopped;
486
0
  if (! INTUSE(dwfl_attach_state) (dwfl, elf, pid, &pid_thread_callbacks,
487
0
           pid_arg))
488
0
    {
489
0
      elf_end (elf);
490
0
      close (elf_fd);
491
0
      closedir (dir);
492
0
      free (pid_arg);
493
0
      return -1;
494
0
    }
495
0
  return 0;
496
0
}
497
INTDEF (dwfl_linux_proc_attach)
498
499
struct __libdwfl_pid_arg *
500
internal_function
501
__libdwfl_get_pid_arg (Dwfl *dwfl)
502
0
{
503
0
  if (dwfl != NULL && dwfl->process != NULL
504
0
      && dwfl->process->callbacks == &pid_thread_callbacks)
505
0
    return (struct __libdwfl_pid_arg *) dwfl->process->callbacks_arg;
506
507
0
  return NULL;
508
0
}
509
510
#else /* __linux__ */
511
512
bool
513
internal_function
514
__libdwfl_ptrace_attach (pid_t tid __attribute__ ((unused)),
515
       bool *tid_was_stoppedp __attribute__ ((unused)))
516
{
517
  errno = ENOSYS;
518
  __libdwfl_seterrno (DWFL_E_ERRNO);
519
  return false;
520
}
521
522
void
523
internal_function
524
__libdwfl_ptrace_detach (pid_t tid __attribute__ ((unused)),
525
       bool tid_was_stopped __attribute__ ((unused)))
526
{
527
}
528
529
int
530
dwfl_linux_proc_attach (Dwfl *dwfl __attribute__ ((unused)),
531
      pid_t pid __attribute__ ((unused)),
532
      bool assume_ptrace_stopped __attribute__ ((unused)))
533
{
534
  return ENOSYS;
535
}
536
INTDEF (dwfl_linux_proc_attach)
537
538
struct __libdwfl_pid_arg *
539
internal_function
540
__libdwfl_get_pid_arg (Dwfl *dwfl __attribute__ ((unused)))
541
{
542
  return NULL;
543
}
544
545
#endif /* ! __linux __ */
546