CUBRID Engine  latest
stack_dump.c
Go to the documentation of this file.
1 /*
2  * Copyright 2008 Search Solution Corporation
3  * Copyright 2016 CUBRID Corporation
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */
18 
19 /*
20  * stack_dump.c - call stack dump
21  */
22 
23 #ident "$Id$"
24 
25 #include "printer.hpp"
26 
27 #if defined(x86_SOLARIS)
28 
29 #include <stdio.h>
30 #include <string.h>
31 #include <unistd.h>
32 #include <fcntl.h>
33 #include <dlfcn.h>
34 #include <ucontext.h>
35 #include <sys/stack.h>
36 #include <sys/frame.h>
37 #include <sys/elf.h>
38 
39 #include "stack_dump.h"
40 
41 #define FRAME_PTR_REGISTER EBP
42 #define TR_ARG_MAX 6
43 #define PGRAB_RDONLY 0x04
44 #define MIN(a,b) ((a) < (b) ? (a) : (b))
45 
46 typedef Elf64_Sym GElf_Sym;
47 
48 extern struct ps_prochandle *Pgrab (pid_t, int, int *);
49 extern void Pfree (struct ps_prochandle *);
50 extern int Plookup_by_addr (struct ps_prochandle *, uintptr_t, char *, size_t, GElf_Sym *);
51 
52 
53 static ulong_t argcount (uintptr_t eip);
54 static int read_safe (int fd, struct frame *fp, struct frame **savefp, uintptr_t * savepc);
55 
56 
57 /*
58  * argcount -
59  * return:
60  * eip(in):
61  */
62 static ulong_t
63 argcount (uintptr_t eip)
64 {
65  const uint8_t *ins = (const uint8_t *) eip;
66  ulong_t n;
67 
68  enum
69  {
70  M_MODRM_ESP = 0xc4, /* Mod/RM byte indicates %esp */
71  M_ADD_IMM32 = 0x81, /* ADD imm32 to r/m32 */
72  M_ADD_IMM8 = 0x83 /* ADD imm8 to r/m32 */
73  };
74 
75  switch (ins[0])
76  {
77  case M_ADD_IMM32:
78  n = ins[2] + (ins[3] << 8) + (ins[4] << 16) + (ins[5] << 24);
79  break;
80 
81  case M_ADD_IMM8:
82  n = ins[2];
83  break;
84 
85  default:
86  return (TR_ARG_MAX);
87  }
88 
89  n /= sizeof (long);
90  return (MIN (n, TR_ARG_MAX));
91 }
92 
93 /*
94  * read_safe -
95  * return:
96  * fd(in):
97  * fp(in):
98  * savefp(in):
99  * savepc(in):
100  */
101 static int
102 read_safe (int fd, struct frame *fp, struct frame **savefp, uintptr_t * savepc)
103 {
104  uintptr_t newfp;
105 
106  if ((uintptr_t) fp & (sizeof (void *) - 1))
107  {
108  return (-1); /* misaligned */
109  }
110 
111  if ((pread (fd, (void *) &newfp, sizeof (fp->fr_savfp), (off_t) & fp->fr_savfp) != sizeof (fp->fr_savfp))
112  || pread (fd, (void *) savepc, sizeof (fp->fr_savpc), (off_t) & fp->fr_savpc) != sizeof (fp->fr_savpc))
113  {
114  return (-1);
115  }
116 
117  if (newfp != 0)
118  {
119  newfp += STACK_BIAS;
120  }
121 
122  *savefp = (struct frame *) newfp;
123 
124  return (0);
125 }
126 
127 /*
128  * log_stack_info -
129  * return:
130  * output(in/out):
131  * pc(in):
132  * argc(in):
133  * argv(in):
134  * Pr(in):
135  */
136 static int
137 log_stack_info (print_output & output, uintptr_t pc, ulong_t argc, long *argv, struct ps_prochandle *Pr)
138 {
139  char buff[255];
140  GElf_Sym sym;
141  uintptr_t start;
142  int i;
143 
144  sprintf (buff, "%.*lx", 8, (long) pc);
145  strcpy (buff + 8, " ????????");
146 
147  if (Plookup_by_addr (Pr, pc, buff + 1 + 8, sizeof (buff) - 1 - 8, &sym) == 0)
148  {
149  start = sym.st_value;
150  }
151  else
152  {
153  start = pc;
154  }
155 
156  output ("%-17s(", buff);
157 
158  for (i = 0; i < argc; i++)
159  {
160  output ((i + 1 == argc) ? "%lx" : "%lx, ", argv[i]);
161  }
162 
163  output ((start != pc) ? ") + %lx\n" : ")\n", (long) (pc - start));
164  output.flush ();
165 
166  return (0);
167 }
168 
169 /*
170  * er_dump_call_stack_internal - dump call stack
171  * return: none
172  * output(in/put):
173  */
174 void
176 {
177  ucontext_t ucp;
178  struct frame *fp, *savefp;
179  ulong_t argc;
180  long *argv;
181  struct ps_prochandle *Pr;
182  int err, fd;
183  uintptr_t savepc;
184 
185  Pr = Pgrab (getpid (), PGRAB_RDONLY, &err);
186  if (Pr == NULL)
187  {
188  return;
189  }
190 
191  if (getcontext (&ucp) < 0)
192  {
193  Pfree (Pr);
194  return;
195  }
196 
197  fp = (struct frame *) ((caddr_t) ucp.uc_mcontext.gregs[FRAME_PTR_REGISTER] + STACK_BIAS);
198 
199  fd = open ("/proc/self/as", O_RDONLY);
200  if (fd < 0)
201  {
202  Pfree (Pr);
203  return;
204  }
205 
206  while (fp != NULL)
207  {
208  if (read_safe (fd, fp, &savefp, &savepc) != 0)
209  {
210  close (fd);
211  Pfree (Pr);
212  return;
213  }
214 
215  /* break when reaches the bottom of stack */
216  if (savefp == NULL)
217  {
218  break;
219  }
220 
221  if (savefp->fr_savfp == 0)
222  {
223  break;
224  }
225 
226  argc = argcount (savepc);
227  argv = (long *) ((char *) savefp + sizeof (struct frame));
228 
229  log_stack_info (output, savepc, argc, argv, Pr);
230  fp = savefp;
231  }
232 
233  close (fd);
234  Pfree (Pr);
235 }
236 
237 #elif defined(LINUX)
238 static int er_resolve_function_name (const void *address, const char *lib_file_name, char *buffer, int buffer_size);
239 
240 #if __WORDSIZE == 32
241 
242 #include <stdio.h>
243 #include <string.h>
244 
245 #include <ucontext.h>
246 #include <dlfcn.h>
247 
248 #include "error_code.h"
249 #include "memory_hash.h"
250 #include "stack_dump.h"
251 
252 #define PEEK_DATA(addr) (*(size_t *)(addr))
253 #define MAXARGS 6
254 #define BUFFER_SIZE 1024
255 
256 /*
257  * er_dump_call_stack_internal - dump call stack
258  * return:
259  * output(in/out):
260  */
261 void
263 {
264  ucontext_t ucp;
265  size_t frame_pointer_addr, next_frame_pointer_addr;
266  size_t return_addr, arg;
267  int i, nargs;
268  Dl_info dl_info;
269  const char *func_name_p;
270  const void *func_addr_p = NULL;
271  char buffer[BUFFER_SIZE];
272 
273  if (getcontext (&ucp) < 0)
274  {
275  return;
276  }
277 
278  return_addr = ucp.uc_mcontext.gregs[REG_EIP];
279  frame_pointer_addr = ucp.uc_mcontext.gregs[REG_EBP];
280 
281  while (frame_pointer_addr)
282  {
283  if (dladdr ((size_t *) return_addr, &dl_info) == 0)
284  {
285  break;
286  }
287 
288  if (dl_info.dli_fbase >= (const void *) 0x40000000)
289  {
290  func_addr_p = (void *) ((size_t) ((const char *) return_addr) - (size_t) dl_info.dli_fbase);
291  }
292  else
293  {
294  func_addr_p = (void *) return_addr;
295  }
296 
297  if (dl_info.dli_sname)
298  {
299  func_name_p = dl_info.dli_sname;
300  }
301  else
302  {
303  if (er_resolve_function_name (func_addr_p, dl_info.dli_fname, buffer, sizeof (buffer)) == NO_ERROR)
304  {
305  func_name_p = buffer;
306  }
307  else
308  {
309  func_name_p = "???";
310  }
311  }
312 
313  output ("%s(%p): %s", dl_info.dli_fname, func_addr_p, func_name_p);
314 
315  next_frame_pointer_addr = PEEK_DATA (frame_pointer_addr);
316  nargs = (next_frame_pointer_addr - frame_pointer_addr - 8) / 4;
317  if (nargs > MAXARGS)
318  {
319  nargs = MAXARGS;
320  }
321 
322  output (" (");
323  if (nargs > 0)
324  {
325  for (i = 1; i <= nargs; i++)
326  {
327  arg = PEEK_DATA (frame_pointer_addr + 4 * (i + 1));
328  output ("%x", arg);
329  if (i < nargs)
330  {
331  output (", ");
332  }
333  }
334  }
335  output (")\n");
336 
337  if (next_frame_pointer_addr == 0)
338  {
339  break;
340  }
341 
342  return_addr = PEEK_DATA (frame_pointer_addr + 4);
343  frame_pointer_addr = next_frame_pointer_addr;
344  }
345 
346  output.flush ();
347 }
348 
349 #else /* __WORDSIZE == 32 */
350 
351 #include <stdio.h>
352 #include <stdlib.h>
353 #include <string.h>
354 #include <dlfcn.h>
355 #include <execinfo.h>
356 
357 #include "error_code.h"
358 #include "memory_hash.h"
359 #include "stack_dump.h"
360 
361 #define MAX_TRACE 32
362 #define BUFFER_SIZE 1024
363 
364 /*
365  * er_dump_call_stack_internal - dump call stack
366  * return:
367  * output(in/out):
368  */
369 void
371 {
372  void *return_addr[MAX_TRACE];
373  int i, trace_count;
374  Dl_info dl_info;
375  const char *func_name_p;
376  const void *func_addr_p;
377  char buffer[BUFFER_SIZE];
378 
379  trace_count = backtrace (return_addr, MAX_TRACE);
380 
381  for (i = 0; i < trace_count; i++)
382  {
383  if (dladdr (return_addr[i], &dl_info) == 0)
384  {
385  break;
386  }
387 
388  if (dl_info.dli_fbase >= (const void *) 0x40000000)
389  {
390  func_addr_p = (void *) ((size_t) ((const char *) return_addr[i]) - (size_t) dl_info.dli_fbase);
391  }
392  else
393  {
394  func_addr_p = return_addr[i];
395  }
396 
397  if (dl_info.dli_sname)
398  {
399  func_name_p = dl_info.dli_sname;
400  }
401  else
402  {
403  if (er_resolve_function_name (func_addr_p, dl_info.dli_fname, buffer, sizeof (buffer)) == NO_ERROR)
404  {
405  func_name_p = buffer;
406  }
407  else
408  {
409  func_name_p = "???";
410  }
411  }
412 
413  output ("%s(%p): %s\n", dl_info.dli_fname, func_addr_p, func_name_p);
414  }
415 
416  output.flush ();
417 }
418 #endif /* __WORDSIZE == 32 */
419 
420 MHT_TABLE *fname_table;
421 
422 static int
423 er_resolve_function_name (const void *address, const char *lib_file_name_p, char *buffer, int buffer_size)
424 {
425  FILE *output;
426  char cmd_line[BUFFER_SIZE];
427  char *func_name_p, *pos;
428  char buf[BUFFER_SIZE], *key, *data;
429 
430  snprintf (buf, BUFFER_SIZE, "%p%s", address, lib_file_name_p);
431  data = (char *) mht_get (fname_table, buf);
432  if (data != NULL)
433  {
434  snprintf (buffer, buffer_size, data);
435  return NO_ERROR;
436  }
437 
438  snprintf (cmd_line, sizeof (cmd_line), "addr2line -f -C -e %s %p 2>/dev/null", lib_file_name_p, address);
439 
440  output = popen (cmd_line, "r");
441  if (!output)
442  {
443  return ER_FAILED;
444  }
445 
446  func_name_p = fgets (buffer, buffer_size - 1, output);
447  if (!func_name_p || !func_name_p[0])
448  {
449  pclose (output);
450  return ER_FAILED;
451  }
452 
453  pos = strchr (func_name_p, '\n');
454  if (pos)
455  {
456  pos[0] = '\0';
457  }
458 
459  pclose (output);
460 
461  key = strdup (buf);
462  if (key == NULL)
463  {
464  return ER_FAILED;
465  }
466 
467  data = strdup (func_name_p);
468  if (data == NULL)
469  {
470  free (key);
471  return ER_FAILED;
472  }
473 
474  if (mht_put (fname_table, key, data) == NULL)
475  {
476  free (key);
477  free (data);
478  return ER_FAILED;
479  }
480  return NO_ERROR;
481 }
482 #else /* LINUX */
483 
484 #include <stdio.h>
485 #include "stack_dump.h"
486 
487 /*
488  * er_dump_call_stack_internal - dump call stack
489  * return:
490  * output(in/out):
491  */
492 void
494 {
495  output ("call stack dump: NOT available in this platform\n");
496 }
497 #endif /* X86_SOLARIS, LINUX */
498 
499 void
500 er_dump_call_stack (FILE * outfp)
501 {
502  file_print_output output (outfp);
504 }
505 
506 char *
508 {
509  string_print_output output;
511  char *ptr = strdup (output.get_buffer ());
512  output.clear ();
513 
514  return ptr;
515 }
#define NO_ERROR
Definition: error_code.h:46
int argc
Definition: dynamic_load.c:951
#define ER_FAILED
Definition: error_code.h:47
const void * mht_put(MHT_TABLE *ht, const void *key, void *data)
Definition: memory_hash.c:1778
virtual int flush(void)=0
void er_dump_call_stack_internal(print_output &output)
Definition: stack_dump.c:493
#define BUFFER_SIZE
Definition: broker.c:106
void * mht_get(MHT_TABLE *ht, const void *key)
Definition: memory_hash.c:1419
#define NULL
Definition: freelistheap.h:34
char * er_dump_call_stack_to_string(void)
Definition: stack_dump.c:507
#define err(fd,...)
Definition: porting.h:431
void clear(void)
Definition: printer.hpp:103
const char ** argv
Definition: dynamic_load.c:952
const char * get_buffer() const
Definition: printer.hpp:98
int i
Definition: dynamic_load.c:954
char * strdup(const char *str)
Definition: porting.c:901
void er_dump_call_stack(FILE *outfp)
Definition: stack_dump.c:500