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 enum {
29 ZEND_GDBJIT_NOACTION,
30 ZEND_GDBJIT_REGISTER,
31 ZEND_GDBJIT_UNREGISTER
32 };
33
34 typedef struct _zend_gdbjit_code_entry {
35 struct _zend_gdbjit_code_entry *next_entry;
36 struct _zend_gdbjit_code_entry *prev_entry;
37 const char *symfile_addr;
38 uint64_t symfile_size;
39 } zend_gdbjit_code_entry;
40
41 typedef struct _zend_gdbjit_descriptor {
42 uint32_t version;
43 uint32_t action_flag;
44 struct _zend_gdbjit_code_entry *relevant_entry;
45 struct _zend_gdbjit_code_entry *first_entry;
46 } zend_gdbjit_descriptor;
47
48 ZEND_API zend_gdbjit_descriptor __jit_debug_descriptor = {
49 1, ZEND_GDBJIT_NOACTION, NULL, NULL
50 };
51
__jit_debug_register_code(void)52 ZEND_API zend_never_inline void __jit_debug_register_code(void)
53 {
54 __asm__ __volatile__("");
55 }
56
zend_gdb_register_code(const void * object,size_t size)57 ZEND_API bool zend_gdb_register_code(const void *object, size_t size)
58 {
59 zend_gdbjit_code_entry *entry;
60
61 entry = malloc(sizeof(zend_gdbjit_code_entry) + size);
62 if (entry == NULL) {
63 return 0;
64 }
65
66 entry->symfile_addr = ((char*)entry) + sizeof(zend_gdbjit_code_entry);
67 entry->symfile_size = size;
68
69 memcpy((char *)entry->symfile_addr, object, size);
70
71 entry->prev_entry = NULL;
72 entry->next_entry = __jit_debug_descriptor.first_entry;
73
74 if (entry->next_entry) {
75 entry->next_entry->prev_entry = entry;
76 }
77 __jit_debug_descriptor.first_entry = entry;
78
79 /* Notify GDB */
80 __jit_debug_descriptor.relevant_entry = entry;
81 __jit_debug_descriptor.action_flag = ZEND_GDBJIT_REGISTER;
82 __jit_debug_register_code();
83
84 return 1;
85 }
86
zend_gdb_unregister_all(void)87 ZEND_API void zend_gdb_unregister_all(void)
88 {
89 zend_gdbjit_code_entry *entry;
90
91 __jit_debug_descriptor.action_flag = ZEND_GDBJIT_UNREGISTER;
92 while ((entry = __jit_debug_descriptor.first_entry)) {
93 __jit_debug_descriptor.first_entry = entry->next_entry;
94 if (entry->next_entry) {
95 entry->next_entry->prev_entry = NULL;
96 }
97 /* Notify GDB */
98 __jit_debug_descriptor.relevant_entry = entry;
99 __jit_debug_register_code();
100
101 free(entry);
102 }
103 }
104
zend_gdb_present(void)105 ZEND_API bool zend_gdb_present(void)
106 {
107 bool ret = 0;
108 int fd = open("/proc/self/status", O_RDONLY);
109
110 if (fd > 0) {
111 char buf[1024];
112 ssize_t n = read(fd, buf, sizeof(buf) - 1);
113 char *s;
114 pid_t pid;
115
116 if (n > 0) {
117 buf[n] = 0;
118 s = strstr(buf, "TracerPid:");
119 if (s) {
120 s += sizeof("TracerPid:") - 1;
121 while (*s == ' ' || *s == '\t') {
122 s++;
123 }
124 pid = atoi(s);
125 if (pid) {
126 char out[1024];
127 sprintf(buf, "/proc/%d/exe", (int)pid);
128 if (readlink(buf, out, sizeof(out) - 1) > 0) {
129 if (strstr(out, "gdb")) {
130 ret = 1;
131 }
132 }
133 }
134 }
135 }
136
137 close(fd);
138 }
139
140 return ret;
141 }
142