zend_gdb.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  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. #include "zend.h"
  20. #include "zend_gdb.h"
  21. #include <sys/types.h>
  22. #include <sys/stat.h>
  23. #include <fcntl.h>
  24. #include <unistd.h>
  25. #if defined(__FreeBSD__)
  26. # include <sys/user.h>
  27. # include <libutil.h>
  28. #endif
  29. enum {
  30. ZEND_GDBJIT_NOACTION,
  31. ZEND_GDBJIT_REGISTER,
  32. ZEND_GDBJIT_UNREGISTER
  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. typedef struct _zend_gdbjit_descriptor {
  41. uint32_t version;
  42. uint32_t action_flag;
  43. struct _zend_gdbjit_code_entry *relevant_entry;
  44. struct _zend_gdbjit_code_entry *first_entry;
  45. } zend_gdbjit_descriptor;
  46. ZEND_API zend_gdbjit_descriptor __jit_debug_descriptor = {
  47. 1, ZEND_GDBJIT_NOACTION, NULL, NULL
  48. };
  49. ZEND_API zend_never_inline void __jit_debug_register_code(void)
  50. {
  51. __asm__ __volatile__("");
  52. }
  53. ZEND_API bool zend_gdb_register_code(const void *object, size_t size)
  54. {
  55. zend_gdbjit_code_entry *entry;
  56. entry = malloc(sizeof(zend_gdbjit_code_entry) + size);
  57. if (entry == NULL) {
  58. return 0;
  59. }
  60. entry->symfile_addr = ((char*)entry) + sizeof(zend_gdbjit_code_entry);
  61. entry->symfile_size = size;
  62. memcpy((char *)entry->symfile_addr, object, size);
  63. entry->prev_entry = NULL;
  64. entry->next_entry = __jit_debug_descriptor.first_entry;
  65. if (entry->next_entry) {
  66. entry->next_entry->prev_entry = entry;
  67. }
  68. __jit_debug_descriptor.first_entry = entry;
  69. /* Notify GDB */
  70. __jit_debug_descriptor.relevant_entry = entry;
  71. __jit_debug_descriptor.action_flag = ZEND_GDBJIT_REGISTER;
  72. __jit_debug_register_code();
  73. return 1;
  74. }
  75. ZEND_API void zend_gdb_unregister_all(void)
  76. {
  77. zend_gdbjit_code_entry *entry;
  78. __jit_debug_descriptor.action_flag = ZEND_GDBJIT_UNREGISTER;
  79. while ((entry = __jit_debug_descriptor.first_entry)) {
  80. __jit_debug_descriptor.first_entry = entry->next_entry;
  81. if (entry->next_entry) {
  82. entry->next_entry->prev_entry = NULL;
  83. }
  84. /* Notify GDB */
  85. __jit_debug_descriptor.relevant_entry = entry;
  86. __jit_debug_register_code();
  87. free(entry);
  88. }
  89. }
  90. ZEND_API bool zend_gdb_present(void)
  91. {
  92. bool ret = 0;
  93. #if defined(__linux__) /* netbsd while having this procfs part, does not hold the tracer pid */
  94. int fd = open("/proc/self/status", O_RDONLY);
  95. if (fd > 0) {
  96. char buf[1024];
  97. ssize_t n = read(fd, buf, sizeof(buf) - 1);
  98. char *s;
  99. pid_t pid;
  100. if (n > 0) {
  101. buf[n] = 0;
  102. s = strstr(buf, "TracerPid:");
  103. if (s) {
  104. s += sizeof("TracerPid:") - 1;
  105. while (*s == ' ' || *s == '\t') {
  106. s++;
  107. }
  108. pid = atoi(s);
  109. if (pid) {
  110. char out[1024];
  111. sprintf(buf, "/proc/%d/exe", (int)pid);
  112. if (readlink(buf, out, sizeof(out) - 1) > 0) {
  113. if (strstr(out, "gdb")) {
  114. ret = 1;
  115. }
  116. }
  117. }
  118. }
  119. }
  120. close(fd);
  121. }
  122. #elif defined(__FreeBSD__)
  123. struct kinfo_proc *proc = kinfo_getproc(getpid());
  124. if (proc) {
  125. if ((proc->ki_flag & P_TRACED) != 0) {
  126. struct kinfo_proc *dbg = kinfo_getproc(proc->ki_tracer);
  127. ret = (dbg && strstr(dbg->ki_comm, "gdb"));
  128. }
  129. }
  130. #endif
  131. return ret;
  132. }