⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 coredumper_unittest.c

📁 能把所有线程的数据和环境记录到文件,方便调试.
💻 C
📖 第 1 页 / 共 2 页
字号:
/* Copyright (c) 2005-2007, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * *     * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. *     * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. *     * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * --- * Author: Markus Gutschke */#include <assert.h>#include <endian.h>#include <errno.h>#include <fcntl.h>#include <pthread.h>#include <setjmp.h>#include <signal.h>#include <stdint.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/stat.h>#include <sys/types.h>#include <unistd.h>#include "google/coredumper.h"#include "linuxthreads.h"/* Simple signal handler for dealing with timeouts.                          */static jmp_buf jmpenv;static void TimeOutHandler(int sig, siginfo_t *info, void *p) {  siglongjmp(jmpenv, sig);}/* This is a really silly CPU hog, but we want to avoid creating a * core dump while we are executing code in libc. Depending on the * system environment, gdb might or might not make stack traces * available within libc, and that would make this unittest * non-deterministic. */static volatile enum State { IDLE, RUNNING, DEAD } state1, state2;static volatile unsigned int counter;static void *Busy(void *arg) {  volatile enum State *state = (volatile enum State *)arg;  *state = RUNNING;  while (*state == RUNNING) {    counter++;  }  return 0;}/* Open the core file with "readelf", and check that all the expected * entries can be found. We are not checking exact numeric values, as these * might differ between runs, and it seems overkill recomputing them here. */static void CheckWithReadElf(FILE *input, FILE *output, const char *filename,                             const char *suffix, const char *decompress,                             const char *args) {  static const char *msg[] = { " ELF",#if __BYTE_ORDER == __LITTLE_ENDIAN                               "little"#else                               "big"#endif                               " endian", "UNIX - System V",                               "Core file", "no sections in this file",                               "NOTE", "no dynamic se",                               "no relocations in this file",                               "no unwind sections in this file",                               "No version information found in this file",                               "NT_PRPSINFO", "NT_TASKSTRUCT",                               "NT_PRSTATUS", "NT_FPREGSET",#ifdef THREADS                               "NT_PRSTATUS", "NT_FPREGSET",                               "NT_PRSTATUS", "NT_FPREGSET",#endif                               "DONE", 0 };  const char  **ptr;  char buffer[4096];  int  rc = fprintf(input,                    "cat /proc/%d/maps &&"                    "%s %s <\"%s%s\" >core.%d &&"                    "readelf -a core.%d; "                    "rm -f core.%d; "                    "(set +x; echo DONE)\n",                    getpid(), decompress, args, filename, suffix,                    getpid(), getpid(), getpid());  assert(rc > 0);  *buffer = '\000';  for (ptr = msg; *ptr; ptr++) {    do {      char *line;      assert(strncmp(buffer, "DONE", 4));      line = fgets(buffer, sizeof(buffer), output);      assert(line);      fputs(buffer, stdout);    } while (!strstr(buffer, *ptr));    printf("Found: %s\n", *ptr);  }  return;}/* Open the core dump with gdb, and check that the stack traces look * correct. Again, we are not checking for exact numeric values. * * We also extract the value of the "dummy" environment variable, and check * that it is correct. */static void CheckWithGDB(FILE *input, FILE *output, const char *filename,                         int *dummy, int cmp_parm) {  volatile int cmp = cmp_parm;  char out[4096], buffer[4096];  char * volatile out_ptr = out;  const char **ptr, *arg = "";  struct sigaction sa;#if defined(__i386__) || defined(__x86_64) || defined(__ARM_ARCH_3__)  /* If we have a platform-specific FRAME() macro, we expect the stack trace   * to be unrolled all the way to WriteCoreDump().   */  #define DUMPFUNCTION "CoreDump"#else  /* Otherwise, we the stack trace will start in ListAllProcessThreads.   */  #define DUMPFUNCTION "ListAllProcessThreads"#endif  /* Messages that we are looking for. "@" is a special character that   * matches a pattern in the output, which can later be used as input   * to gdb. "*" is a glob wildcard character.   */  static const char *msg[] = { "Core was generated by",                               " @ process * *"DUMPFUNCTION,                               "[Switching to thread * *"DUMPFUNCTION,                               "#* *CoreDump",                               "#@ * TestCoreDump",                               " TestCoreDump",                               "$1 = ",#ifdef THREADS                               " Busy",                               " @ process * Busy",                               "[Switching to thread * Busy",                               "Busy",                               "Busy",#endif                               "DONE", 0 };  /* Commands that we are sending to gdb. All occurrences of "@" will be   * substituted with the pattern matching the corresponding "@" character   * in the stream of messages received.   */  sprintf(out,          "gdb /proc/%d/exe \"%s\"; (set +x; echo DONE)\n"          "info threads\n"          "thread @\n"          "bt 10\n"          "up @\n"          "print *(unsigned int *)0x%lx\n"          "print %dU\n"          "print %dU\n"#ifdef THREADS          "info threads\n"          "thread @\n"          "thread apply all bt 10\n"#endif          "quit\n",          getpid(), filename,          (unsigned long)dummy, *dummy, cmp);  /* Since we are interactively driving gdb, it is possible that we would   * indefinitely have to wait for a matching message to appear (this is   * different from the "readelf" case, which can just read until EOF).   * So, we have to set up a time out handler.   */  memset(&sa, 0, sizeof(sa));  sa.sa_sigaction = TimeOutHandler;  sa.sa_flags     = SA_RESTART|SA_SIGINFO;  sigaction(SIGALRM, &sa, 0);  if (setjmp(jmpenv)) {    puts("Time out!");    abort();  } else {    *buffer = '\000';    for (ptr = msg; *ptr; ptr++) {      /* If there is any command that does not require a pattern read from       * the message stream, output it now.       */      while (*out_ptr && *out_ptr != '@') {        int rc = putc(*out_ptr++, input);        assert(rc >= 0);      }      fflush(input);      for (;;) {        char *line, *templ, scratch[256], isarg = 0;        /* We should never try to read any more messages, after we have         * already seen the final "DONE" message.         */        assert(strncmp(buffer, "DONE", 4));        /* Read the next message from gdb.                                   */        alarm(4);        line = fgets(buffer, sizeof(buffer), output);        alarm(0);        assert(line);        fputs(buffer, stdout);        /* Extract the "$1 =" string, which we will compare later.           */        if ((arg = strstr(buffer, "$1 = ")) != NULL) {          cmp = atoi(arg + 5);          arg = 0;        }        /* Try to match the current line against our templates.              */        templ = strcpy(scratch, *ptr);        for (;;) {          /* Split the template in substring separated by "@" and "*" chars. */          int  l = strcspn(templ, "*@");          char c = templ[l];          templ[l] = '\000';          /* If we just passed a "@", remember pattern for later use.        */          if (isarg) {            arg = line;            isarg = 0;          }          if (c == '@')            isarg++;          /* Check if substring of template matches somewhere in current line*/          if ((line = strstr(line, templ)) != NULL) {            /* Found a match. Remember arg, if any.                          */            if (c != '@')              *line = '\000';            /* Advance to next pattern that needs matching.                  */            line += strlen(templ);          } else {            /* No match. Break out of this loop, and read next line.         */            templ[l] = c;            arg = 0;            break;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -