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
__jit_debug_register_code(void)57 ZEND_API zend_never_inline void __jit_debug_register_code(void)
58 {
59 __asm__ __volatile__("");
60 }
61
zend_gdb_register_code(const void * object,size_t size)62 ZEND_API bool zend_gdb_register_code(const void *object, size_t size)
63 {
64 zend_gdbjit_code_entry *entry;
65
66 entry = malloc(sizeof(zend_gdbjit_code_entry) + size);
67 if (entry == NULL) {
68 return 0;
69 }
70
71 entry->symfile_addr = ((char*)entry) + sizeof(zend_gdbjit_code_entry);
72 entry->symfile_size = size;
73
74 memcpy((char *)entry->symfile_addr, object, size);
75
76 entry->prev_entry = NULL;
77 entry->next_entry = __jit_debug_descriptor.first_entry;
78
79 if (entry->next_entry) {
80 entry->next_entry->prev_entry = entry;
81 }
82 __jit_debug_descriptor.first_entry = entry;
83
84 /* Notify GDB */
85 __jit_debug_descriptor.relevant_entry = entry;
86 __jit_debug_descriptor.action_flag = ZEND_GDBJIT_REGISTER;
87 __jit_debug_register_code();
88
89 return 1;
90 }
91
zend_gdb_unregister_all(void)92 ZEND_API void zend_gdb_unregister_all(void)
93 {
94 zend_gdbjit_code_entry *entry;
95
96 __jit_debug_descriptor.action_flag = ZEND_GDBJIT_UNREGISTER;
97 while ((entry = __jit_debug_descriptor.first_entry)) {
98 __jit_debug_descriptor.first_entry = entry->next_entry;
99 if (entry->next_entry) {
100 entry->next_entry->prev_entry = NULL;
101 }
102 /* Notify GDB */
103 __jit_debug_descriptor.relevant_entry = entry;
104 __jit_debug_register_code();
105
106 free(entry);
107 }
108 }
109
zend_gdb_present(void)110 ZEND_API bool zend_gdb_present(void)
111 {
112 bool ret = 0;
113 #if defined(__linux__) /* netbsd while having this procfs part, does not hold the tracer pid */
114 int fd = open("/proc/self/status", O_RDONLY);
115
116 if (fd >= 0) {
117 char buf[1024];
118 ssize_t n = read(fd, buf, sizeof(buf) - 1);
119 char *s;
120 pid_t pid;
121
122 if (n > 0) {
123 buf[n] = 0;
124 s = strstr(buf, "TracerPid:");
125 if (s) {
126 s += sizeof("TracerPid:") - 1;
127 while (*s == ' ' || *s == '\t') {
128 s++;
129 }
130 pid = atoi(s);
131 if (pid) {
132 char out[1024];
133 snprintf(buf, sizeof(buf), "/proc/%d/exe", (int)pid);
134 if (readlink(buf, out, sizeof(out) - 1) > 0) {
135 if (strstr(out, "gdb")) {
136 ret = 1;
137 }
138 }
139 }
140 }
141 }
142
143 close(fd);
144 }
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 return ret;
158 }
159