gdb.cc 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. /*
  2. * Copyright [2021] JD.com, Inc.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. *
  16. */
  17. #include <stdio.h>
  18. #include <unistd.h>
  19. #include <string.h>
  20. #include <stdlib.h>
  21. #include <ctype.h>
  22. #include "gdb.h"
  23. #include "log/log.h"
  24. #define printf(fmt, args...) log4cplus_bare(2, fmt, ##args)
  25. struct frame_t
  26. {
  27. int index;
  28. /* 0 normal, 1 *this, 2 signal */
  29. int ftype;
  30. };
  31. static void wait_prompt(FILE *outfp)
  32. {
  33. char buf[1024];
  34. while (fgets(buf, sizeof(buf) - 1, outfp)) {
  35. if (!strncmp(buf, "GDB>", 4))
  36. break;
  37. }
  38. }
  39. static void dump_result(FILE *outfp)
  40. {
  41. char buf[1024];
  42. while (fgets(buf, sizeof(buf) - 1, outfp)) {
  43. if (!strncmp(buf, "GDB>", 4))
  44. break;
  45. printf("%s", buf);
  46. }
  47. }
  48. static void parse_frame(FILE *outfp, std::vector<frame_t> &frame)
  49. {
  50. char buf[1024];
  51. int first = 1;
  52. while (fgets(buf, sizeof(buf) - 1, outfp)) {
  53. if (!strncmp(buf, "GDB>", 4))
  54. break;
  55. printf("%s", buf);
  56. if (buf[0] == '#') {
  57. struct frame_t f;
  58. char *p = strstr(buf, "this");
  59. f.index = atoi(buf + 1);
  60. f.ftype = p && (!isalnum(p[-1] && !isalnum(p[4])));
  61. if (first && strstr(buf, "signal handler called") != NULL) {
  62. first = 0;
  63. frame.clear();
  64. f.ftype = 2;
  65. }
  66. frame.push_back(f);
  67. }
  68. }
  69. }
  70. static void dump_info(int pid)
  71. {
  72. char fn[64];
  73. char buf[1024];
  74. int rv;
  75. printf("Process/Thread %d Crashed\n", pid);
  76. snprintf(fn, sizeof(fn), "/proc/%d/exe", pid);
  77. rv = readlink(fn, buf, sizeof(buf) - 1);
  78. if (rv > 0) {
  79. buf[rv] = 0;
  80. printf("Executable: %s\n", buf);
  81. }
  82. snprintf(fn, sizeof(fn), "/proc/%d/cwd", pid);
  83. rv = readlink(fn, buf, sizeof(buf) - 1);
  84. if (rv > 0) {
  85. buf[rv] = 0;
  86. printf("Working Directory: %s\n", buf);
  87. }
  88. snprintf(fn, sizeof(fn), "/proc/%d/cmdline", pid);
  89. FILE *fp = fopen(fn, "r");
  90. if (fp) {
  91. if (fgets(buf, sizeof(buf), fp))
  92. printf("Command Line: %s\n", buf);
  93. fclose(fp);
  94. }
  95. snprintf(fn, sizeof(fn), "/proc/%d/maps", pid);
  96. fp = fopen(fn, "r");
  97. if (fp) {
  98. printf("Dump memory maps:\n");
  99. while (fgets(buf, sizeof(buf), fp)) {
  100. printf(" %s", buf);
  101. }
  102. fclose(fp);
  103. }
  104. }
  105. void gdb_dump(int pid)
  106. {
  107. std::vector<frame_t> frame;
  108. int pcmd[2] = {0,0};
  109. int pout[2] = {0,0};
  110. int ret = 0;
  111. if(ret == 0) {
  112. ret = pipe(pcmd);
  113. ret = pipe(pout);
  114. }
  115. if (fork() == 0) {
  116. dup2(pcmd[0], 0);
  117. dup2(pout[1], 1);
  118. dup2(pout[1], 2);
  119. close(pcmd[0]);
  120. close(pcmd[1]);
  121. close(pout[0]);
  122. close(pout[1]);
  123. execlp("gdb", "gdb", NULL);
  124. exit(1);
  125. }
  126. close(pcmd[0]);
  127. close(pout[1]);
  128. /* always succ because the fd is valid */
  129. FILE *cmdfp = fdopen(pcmd[1], "w");
  130. FILE *outfp = fdopen(pout[0], "r");
  131. setbuf(cmdfp, NULL);
  132. setbuf(outfp, NULL);
  133. fprintf(cmdfp, "set prompt GDB>\\n\n\n");
  134. fflush(cmdfp);
  135. wait_prompt(outfp);
  136. fprintf(cmdfp, "attach %d\n", pid);
  137. dump_info(pid);
  138. dump_result(outfp);
  139. printf("(gdb) backtrace\n");
  140. fprintf(cmdfp, "backtrace\n");
  141. parse_frame(outfp, frame);
  142. #define DUMP(fmt, args...) \
  143. do \
  144. { \
  145. printf("(gdb) " fmt "\n", ##args); \
  146. fprintf(cmdfp, fmt "\n", ##args); \
  147. dump_result(outfp); \
  148. } while (0)
  149. for (unsigned int i = 0; i < frame.size(); i++) {
  150. DUMP("frame %d", frame[i].index);
  151. if (frame[i].ftype <= 1)
  152. DUMP("info locals");
  153. if (frame[i].ftype == 1)
  154. DUMP("print *this");
  155. if (frame[i].ftype == 2)
  156. DUMP("info registers");
  157. }
  158. fprintf(cmdfp, "set variable crash_continue = 1\n");
  159. dump_result(outfp);
  160. fprintf(cmdfp, "quit\n");
  161. fclose(cmdfp);
  162. fclose(outfp);
  163. }
  164. void gdb_attach(int pid, const char *fn)
  165. {
  166. int ret;
  167. if (fn == NULL)
  168. fn = getenv("DISPLAY");
  169. char buf[256];
  170. if (fn == NULL || !fn[0] || !strcmp(fn, "screen")) {
  171. snprintf(buf, sizeof(buf), "screen -X -S gdb screen -t gdb.%d gdb /proc/%d/exe %d", pid, pid, pid);
  172. ret = system(buf);
  173. if (ret != 0) {
  174. snprintf(buf, sizeof(buf), "screen -S gdb -t gdb.%d -d -m gdb /proc/%d/exe %d", pid, pid, pid);
  175. ret = system(buf);
  176. }
  177. } else {
  178. snprintf(buf, sizeof(buf), "xterm -T gdb.%d -e gdb /proc/%d/exe %d &", pid, pid, pid);
  179. ret = system(buf);
  180. }
  181. dump_info(pid);
  182. }