Coverage Report

Created: 2025-06-13 06:43

/src/php-src/Zend/zend_gdb.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
   +----------------------------------------------------------------------+
3
   | Zend Engine                                                          |
4
   +----------------------------------------------------------------------+
5
   | Copyright (c) Zend Technologies Ltd. (http://www.zend.com)           |
6
   +----------------------------------------------------------------------+
7
   | This source file is subject to version 2.00 of the Zend license,     |
8
   | that is bundled with this package in the file LICENSE, and is        |
9
   | available through the world-wide-web at the following url:           |
10
   | http://www.zend.com/license/2_00.txt.                                |
11
   | If you did not receive a copy of the Zend license and are unable to  |
12
   | obtain it through the world-wide-web, please send a note to          |
13
   | license@zend.com so we can mail you a copy immediately.              |
14
   +----------------------------------------------------------------------+
15
   | Authors: Dmitry Stogov <dmitry@zend.com>                             |
16
   |          Xinchen Hui <xinchen.h@zend.com>                            |
17
   +----------------------------------------------------------------------+
18
*/
19
20
#include "zend.h"
21
#include "zend_gdb.h"
22
23
#include <sys/types.h>
24
#include <sys/stat.h>
25
#include <fcntl.h>
26
#include <unistd.h>
27
28
#if defined(__FreeBSD__) && __FreeBSD_version >= 1100000
29
# include <sys/user.h>
30
# include <libutil.h>
31
#endif
32
33
enum {
34
  ZEND_GDBJIT_NOACTION,
35
  ZEND_GDBJIT_REGISTER,
36
  ZEND_GDBJIT_UNREGISTER
37
};
38
39
typedef struct _zend_gdbjit_code_entry {
40
  struct _zend_gdbjit_code_entry *next_entry;
41
  struct _zend_gdbjit_code_entry *prev_entry;
42
  const char                     *symfile_addr;
43
  uint64_t                        symfile_size;
44
} zend_gdbjit_code_entry;
45
46
typedef struct _zend_gdbjit_descriptor {
47
  uint32_t                         version;
48
  uint32_t                         action_flag;
49
  struct _zend_gdbjit_code_entry *relevant_entry;
50
  struct _zend_gdbjit_code_entry *first_entry;
51
} zend_gdbjit_descriptor;
52
53
ZEND_API zend_gdbjit_descriptor __jit_debug_descriptor = {
54
  1, ZEND_GDBJIT_NOACTION, NULL, NULL
55
};
56
57
ZEND_API zend_never_inline void __jit_debug_register_code(void)
58
0
{
59
0
  __asm__ __volatile__("");
60
0
}
61
62
ZEND_API bool zend_gdb_register_code(const void *object, size_t size)
63
0
{
64
0
  zend_gdbjit_code_entry *entry;
65
66
0
  entry = malloc(sizeof(zend_gdbjit_code_entry) + size);
67
0
  if (entry == NULL) {
68
0
    return 0;
69
0
  }
70
71
0
  entry->symfile_addr = ((char*)entry) + sizeof(zend_gdbjit_code_entry);
72
0
  entry->symfile_size = size;
73
74
0
  memcpy((char *)entry->symfile_addr, object, size);
75
76
0
  entry->prev_entry = NULL;
77
0
  entry->next_entry = __jit_debug_descriptor.first_entry;
78
79
0
  if (entry->next_entry) {
80
0
    entry->next_entry->prev_entry = entry;
81
0
  }
82
0
  __jit_debug_descriptor.first_entry = entry;
83
84
  /* Notify GDB */
85
0
  __jit_debug_descriptor.relevant_entry = entry;
86
0
  __jit_debug_descriptor.action_flag = ZEND_GDBJIT_REGISTER;
87
0
  __jit_debug_register_code();
88
89
0
  return 1;
90
0
}
91
92
ZEND_API void zend_gdb_unregister_all(void)
93
0
{
94
0
  zend_gdbjit_code_entry *entry;
95
96
0
  __jit_debug_descriptor.action_flag = ZEND_GDBJIT_UNREGISTER;
97
0
  while ((entry = __jit_debug_descriptor.first_entry)) {
98
0
    __jit_debug_descriptor.first_entry = entry->next_entry;
99
0
    if (entry->next_entry) {
100
0
      entry->next_entry->prev_entry = NULL;
101
0
    }
102
    /* Notify GDB */
103
0
    __jit_debug_descriptor.relevant_entry = entry;
104
0
    __jit_debug_register_code();
105
106
0
    free(entry);
107
0
  }
108
0
}
109
110
ZEND_API bool zend_gdb_present(void)
111
0
{
112
0
  bool ret = 0;
113
0
#if defined(__linux__) /* netbsd while having this procfs part, does not hold the tracer pid */
114
0
  int fd = open("/proc/self/status", O_RDONLY);
115
116
0
  if (fd >= 0) {
117
0
    char buf[1024];
118
0
    ssize_t n = read(fd, buf, sizeof(buf) - 1);
119
0
    char *s;
120
0
    pid_t pid;
121
122
0
    if (n > 0) {
123
0
      buf[n] = 0;
124
0
      s = strstr(buf, "TracerPid:");
125
0
      if (s) {
126
0
        s += sizeof("TracerPid:") - 1;
127
0
        while (*s == ' ' || *s == '\t') {
128
0
          s++;
129
0
        }
130
0
        pid = atoi(s);
131
0
        if (pid) {
132
0
          char out[1024];
133
0
          snprintf(buf, sizeof(buf), "/proc/%d/exe", (int)pid);
134
0
          if (readlink(buf, out, sizeof(out) - 1) > 0) {
135
0
            if (strstr(out, "gdb")) {
136
0
              ret = 1;
137
0
            }
138
0
          }
139
0
        }
140
0
      }
141
0
    }
142
143
0
    close(fd);
144
0
  }
145
#elif defined(__FreeBSD__) && __FreeBSD_version >= 1100000
146
    struct kinfo_proc *proc = kinfo_getproc(getpid());
147
148
    if (proc) {
149
        if ((proc->ki_flag & P_TRACED) != 0) {
150
            struct kinfo_proc *dbg = kinfo_getproc(proc->ki_tracer);
151
152
            ret = (dbg && strstr(dbg->ki_comm, "gdb"));
153
        }
154
    }
155
#endif
156
157
0
  return ret;
158
0
}