diff options
Diffstat (limited to 'libglusterfs/src/common-utils.c')
-rw-r--r-- | libglusterfs/src/common-utils.c | 116 |
1 files changed, 116 insertions, 0 deletions
diff --git a/libglusterfs/src/common-utils.c b/libglusterfs/src/common-utils.c index ec2f07ec994..3a2e557c62b 100644 --- a/libglusterfs/src/common-utils.c +++ b/libglusterfs/src/common-utils.c @@ -3275,3 +3275,119 @@ gf_set_timestamp (const char *src, const char* dest) out: return ret; } + +static void +gf_backtrace_end (char *buf, size_t frames) +{ + size_t pos = 0; + + if (!buf) + return; + + pos = strlen (buf); + + frames = min(frames, GF_BACKTRACE_LEN - pos -1); + + if (frames <= 0) + return; + + memset (buf+pos, ')', frames); + buf[pos+frames] = '\0'; +} + +/*Returns bytes written*/ +static int +gf_backtrace_append (char *buf, size_t pos, char *framestr) +{ + if (pos >= GF_BACKTRACE_LEN) + return -1; + return snprintf (buf+pos, GF_BACKTRACE_LEN-pos, "(--> %s ", framestr); +} + +static int +gf_backtrace_fillframes (char *buf) +{ + void *array[GF_BACKTRACE_FRAME_COUNT]; + size_t frames = 0; + FILE *fp = NULL; + char callingfn[GF_BACKTRACE_FRAME_COUNT-2][1024] = {{0},}; + int ret = -1; + int fd = -1; + size_t idx = 0; + size_t pos = 0; + size_t inc = 0; + char tmpl[32] = "/tmp/btXXXXXX"; + + frames = backtrace (array, GF_BACKTRACE_FRAME_COUNT); + if (!frames) + return -1; + + fd = gf_mkostemp (tmpl, 0, O_RDWR); + if (fd == -1) + return -1; + + /*The most recent two frames are the calling function and + * gf_backtrace_save, which we can infer.*/ + + backtrace_symbols_fd (&array[2], frames-2, fd); + + fp = fdopen (fd, "r"); + if (!fp) { + close (fd); + ret = -1; + goto out; + } + + ret = fseek (fp, 0L, SEEK_SET); + if (ret) + goto out; + + pos = 0; + for (idx = 0; idx < frames - 2; idx++) { + ret = fscanf (fp, "%s", callingfn[idx]); + if (ret == EOF) + break; + inc = gf_backtrace_append (buf, pos, callingfn[idx]); + if (inc == -1) + break; + pos += inc; + } + gf_backtrace_end (buf, idx); + +out: + if (fp) + fclose (fp); + + unlink (tmpl); + + return (idx > 0)? 0: -1; + +} + +/* Optionally takes @buf to save backtrace. If @buf is NULL, uses the + * pre-allocated ctx->btbuf to avoid allocating memory while printing + * backtrace. + * TODO: This API doesn't provide flexibility in terms of no. of frames + * of the backtrace is being saved in the buffer. Deferring fixing it + * when there is a real-use for that.*/ + +char * +gf_backtrace_save (char *buf) +{ + char *bt = NULL; + + if (!buf) { + bt = THIS->ctx->btbuf; + GF_ASSERT (bt); + + } else { + bt = buf; + + } + + if ((0 == gf_backtrace_fillframes (bt))) + return bt; + + gf_log (THIS->name, GF_LOG_WARNING, "Failed to save the backtrace."); + return NULL; +} |