Как автоматически генерировать трассировку стека при сбое моей программы

:

  • library (httr)
  • library (jsonlite)

У меня возникли проблемы с преобразованием json в dataframe / CSV. Для моего случая я сделал:

Token <- "245432532532"
source <- "http://......."
header_type <- "applcation/json"
full_token <- paste0("Bearer ", Token)
response <- GET(n_source, add_headers(Authorization = full_token, Accept = h_type), timeout(120), verbose())
text_json <- content(response, type = 'text', encoding = "UTF-8")
jfile <- fromJSON(text_json)
df <- as.data.frame(jfile)

, затем от df до csv.

В этом формате должно быть легко преобразовать его в несколько CSV, если это необходимо.

Важной частью функции контента должно быть type = 'text'.

539
задан jww 15 September 2018 в 18:56
поделиться

18 ответов

Для Linux и я верю Mac OS X, если Вы используете gcc или какой-либо компилятор, который использует glibc, можно использовать след () функции в execinfo.h, чтобы распечатать stacktrace и выйти корректно, когда Вы получаете отказ сегментации. Документация может быть найдена в libc руководстве .

, Вот пример программы, который устанавливает SIGSEGV обработчик и печатает stacktrace к stderr когда он segfaults. Эти baz() функция здесь вызывает segfault, который инициировал обработчик:

#include <stdio.h>
#include <execinfo.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>


void handler(int sig) {
  void *array[10];
  size_t size;

  // get void*'s for all entries on the stack
  size = backtrace(array, 10);

  // print out all the frames to stderr
  fprintf(stderr, "Error: signal %d:\n", sig);
  backtrace_symbols_fd(array, size, STDERR_FILENO);
  exit(1);
}

void baz() {
 int *foo = (int*)-1; // make a bad pointer
  printf("%d\n", *foo);       // causes segfault
}

void bar() { baz(); }
void foo() { bar(); }


int main(int argc, char **argv) {
  signal(SIGSEGV, handler);   // install our handler
  foo(); // this will call foo, bar, and baz.  baz segfaults.
}

Компиляция с -g -rdynamic получает Вас информация о символе в Вашем выводе, который glibc может использовать для создания хорошего stacktrace:

$ gcc -g -rdynamic ./test.c -o test

Выполнение этого получает Вас этот вывод:

$ ./test
Error: signal 11:
./test(handler+0x19)[0x400911]
/lib64/tls/libc.so.6[0x3a9b92e380]
./test(baz+0x14)[0x400962]
./test(bar+0xe)[0x400983]
./test(foo+0xe)[0x400993]
./test(main+0x28)[0x4009bd]
/lib64/tls/libc.so.6(__libc_start_main+0xdb)[0x3a9b91c4bb]
./test[0x40086a]

Это показывает загрузочный модуль, смещение и функцию, что каждый кадр в стеке прибыл из. Здесь Вы видите обработчик сигналов сверху стека и функции libc прежде main в дополнение к main, foo, bar, и baz.

467
ответ дан Violet Giraffe 15 September 2018 в 18:56
поделиться
  • 1
    Поскольку, когда действие входят onPause() и возвращается с onResume(), загрузчик уведомляется и будет звонить onStartLoading() снова. Так takeContentChanged() (если onContentChanged() был назван ранее) вызовет для обновления mCursor с последними доступными изменениями. Однако на первом if I' d помещенный вместо этого if (mCursor != null && !takeContentChanged()). – AxeEffect 23 February 2014 в 17:05

Посмотрите средство Отслеживания стека в (адаптивная коммуникационная среда) ACE . Это уже записано для покрытия всех основных платформ (и больше). Библиотека является BSD-стилем, лицензируемым, таким образом, Вы можете даже скопировать/вставить код, если Вы не хотите использовать ACE.

6
ответ дан Adam Mitz 15 September 2018 в 18:56
поделиться

Могло бы стоить посмотреть Google Breakpad , межплатформенный генератор дампа катастрофического отказа и инструменты для обработки дампов.

33
ответ дан Fabio Turati 15 September 2018 в 18:56
поделиться

Ive, смотря на эту проблему некоторое время.

И проложенный под землей глубоко в Google Performance Tools README

http://code.google.com/p/google-perftools/source/browse/trunk/README

переговоры о libunwind

http://www.nongnu.org/libunwind/

Хотели бы услышать мнения этой библиотеки.

проблема с-rdynamic состоит в том, что он может увеличить размер двоичного файла относительно значительно в некоторых случаях

10
ответ дан Gregory 15 September 2018 в 18:56
поделиться

Некоторые версии libc содержат функции то соглашение с отслеживаниями стека; Вы могли бы быть в состоянии использовать их:

http://www.gnu.org/software/libc/manual/html_node/Backtraces.html

я не забываю использовать libunwind давным-давно для получения отслеживаний стека, но он не может поддерживаться на платформе.

9
ответ дан Stephen Deken 15 September 2018 в 18:56
поделиться

Посмотрите на:

человек 3 следа

И:

#include <exeinfo.h>
int backtrace(void **buffer, int size);

Это расширения GNU.

6
ответ дан Stéphane 15 September 2018 в 18:56
поделиться
  • 1
    Спасибо за подсказку. Для нашего случая это было вызвано пулом приложений с помощью.Net 2.0 вместо 4,0. – Hong 18 June 2012 в 14:43

Вы не определили свою операционную систему, таким образом, на это трудно ответить. При использовании системы на основе гну libc Вы могли бы быть в состоянии использовать функцию libc backtrace().

GCC также имеет два builtins, которые могут помочь Вам, но которые могут или не могут быть реализованы полностью на Вашей архитектуре, и те __builtin_frame_address и __builtin_return_address. Оба из которых хотят непосредственный целочисленный уровень (непосредственным, я имею в виду, это не может быть переменная). Если __builtin_frame_address для данного уровня является ненулевым, должно быть безопасно захватить обратный адрес того же уровня.

21
ответ дан user 15 September 2018 в 18:56
поделиться
ulimit -c unlimited

системная переменная, которая позволит создавать дамп ядра после Ваших сбоев приложения. В этом случае неограниченная сумма. Ищите файл, названный ядром в том же самом каталоге. Удостоверьтесь, что Вы скомпилировали свой код с включенными отладочными информациями!

отношения

8
ответ дан mana 15 September 2018 в 18:56
поделиться

Важно отметить что, как только Вы генерируете базовый файл, необходимо будет использовать gdb инструмент для рассмотрения его. Для gdb для понимания базового файла необходимо сказать gcc оснащать двоичный файл с отладочной информацией: чтобы сделать это, Вы компилируете с флагом-g:

$ g++ -g prog.cpp -o prog

Затем можно или установить "ulimit-c неограниченный", чтобы позволить ему вывести ядро, или просто запустить программу внутри gdb. Мне нравится второй подход больше:

$ gdb ./prog
... gdb startup output ...
(gdb) run
... program runs and crashes ...
(gdb) where
... gdb outputs your stack trace ...

я надеюсь, что это помогает.

10
ответ дан Benson 15 September 2018 в 18:56
поделиться
  • 1
    Осторожный с вышеупомянутым, getImageMatrix () документы указывают " не изменяйте эту матрицу на месте. Если Вы хотите различную матрицу, относился к drawable, несомненно, назовут setImageMatrix () ". однако setImageMatrix () делает проверку и не будет делать недействительным представление, если локальная матрица, mMatrix.equals (матрица передала в). Следовательно я рекомендовал бы: Матрица m = новая Матрица (); m.reset (); по getImageMatrix () в этом экземпляре. – Twice Circled 29 June 2013 в 14:10

победа: как насчет StackWalk64 http://msdn.microsoft.com/en-us/library/ms680650.aspx

8
ответ дан Roskoto 15 September 2018 в 18:56
поделиться

Я забыл о технологии GNOME "apport", но я не знаю много об использовании его. Это используется для генерации stacktraces и другой диагностики для обработки и может автоматически зарегистрировать ошибки. К этому, конечно, стоит зарегистрироваться.

0
ответ дан 15 September 2018 в 18:56
поделиться
  • 1
    " На архитектуре с (например), 9-разрядным байтом, это won' t быть доступным вообще; Возможно, интересный упомянуть то, что исходное определение POSIX intN_t (как расширение C90) позволило дополнять, таким образом, у Вас могло быть 72-разрядное int64_t из которых 8 битов используются для дополнения. –  16 February 2012 в 20:27

ulimit -c <value> устанавливает базовый предел размера файла для Unix. По умолчанию базовый предел размера файла 0. Вы видите Ваш ulimit значения с ulimit -a.

также, если Вы запускаете свою программу из gdb, она остановит Вашу программу на "нарушениях сегментации" (SIGSEGV, обычно при доступе к части памяти, которую Вы не выделили), или можно установить точки останова.

ddd и nemiver являются фронтендами для gdb, которые делают работу с ним намного легче для новичка.

12
ответ дан user 15 September 2018 в 18:56
поделиться

*nix: можно прервать SIGSEGV (обычно, этот сигнал повышен прежде, чем отказать), и сохраните информацию в файл. (помимо базового файла, который можно использовать для отладки использования gdb, например).

победа: Проверьте это из MSDN.

можно также посмотреть на хромовый код Google, чтобы видеть, как он обрабатывает катастрофические отказы. Это имеет хороший механизм обработки исключений.

4
ответ дан INS 16 September 2018 в 04:56
поделиться
  • 1
    Проблема решена. Ссылка, которую Вы предоставили, дает весь " theory" но может легко смутить программистов-любителей из-за низкоуровневых деталей и смещений. Однако это, кажется, точно описывает механизм внизу. – kstratis 26 March 2012 в 11:41

Я использовал бы код, который генерирует отслеживание стека для пропущенной памяти в Визуальный Детектор Утечки . Это только работает над Win32, все же.

3
ответ дан Jim Buck 16 September 2018 в 04:56
поделиться
  • 1
    Я все еще немного смущен..! Предположим, что я определяю структуру MPI и теперь хочу использовать ее. Ссылка Вы дали состояния: MPI_Type_create_struct (5, array_of_block_lengths, array_of_displacements, array_of_types, & new_type); Если я теперь делаю что-то как myCar =& new_type? – kstratis 26 March 2012 в 10:07

Я могу помочь с версией Linux: функциональный след, backtrace_symbols и backtrace_symbols_fd может использоваться. См. соответствующие страницы руководства.

5
ответ дан terminus 16 September 2018 в 04:56
поделиться

На базовых файлах использования Linux/unix/MacOSX (можно включить им с ulimit или совместимый системный вызов ). На сообщении об ошибке Microsoft использования Windows (можно стать партнером и получить доступ к данным сбоя приложения).

1
ответ дан Kasprzol 16 September 2018 в 04:56
поделиться
  • 1
    исправьте меня, если я неправ: о int64_t, если у меня есть платформа на 8 битов, она будет определенный, и если у меня есть другая платформа, которая не составляет 64 бита, которые она не определит, что в порядке?; о int_least64_t: это определит, только если у меня есть платформа на 64 бита, по крайней мере, или большой, чем платформа на 64 бита, но если платформа меньше чем 64 бита, которые это не определит, будет то, что верный и в последнем int_fast64_t значение по умолчанию, например, если у меня будет платформа на 64 бита, то это будет определенный как _int64 если я и так далее, но с условием быть архитектурой на 8 битов, по крайней мере, и спасибо. – user722528 17 February 2012 в 07:52

Linux

Хотя использование функций backtrace () в execinfo.h для печати трассировки стека и корректного выхода при возникновении ошибки сегментации уже предлагалось , Я не вижу упоминания о тонкостях, необходимых для обеспечения того, чтобы результирующая обратная трассировка указывала на фактическое местоположение неисправности (по крайней мере, для некоторых архитектур - x86 и ARM).

Первые две записи в цепочке кадров стека, когда вы попадаете в обработчик сигнала содержит адрес возврата внутри обработчика сигнала и один адрес внутри sigaction () в libc. Фрейм стека последней функции, вызванной перед сигналом (который является местом ошибки), потерян.

Код

#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#ifndef __USE_GNU
#define __USE_GNU
#endif

#include <execinfo.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ucontext.h>
#include <unistd.h>

/* This structure mirrors the one found in /usr/include/asm/ucontext.h */
typedef struct _sig_ucontext {
 unsigned long     uc_flags;
 struct ucontext   *uc_link;
 stack_t           uc_stack;
 struct sigcontext uc_mcontext;
 sigset_t          uc_sigmask;
} sig_ucontext_t;

void crit_err_hdlr(int sig_num, siginfo_t * info, void * ucontext)
{
 void *             array[50];
 void *             caller_address;
 char **            messages;
 int                size, i;
 sig_ucontext_t *   uc;

 uc = (sig_ucontext_t *)ucontext;

 /* Get the address at the time the signal was raised */
#if defined(__i386__) // gcc specific
 caller_address = (void *) uc->uc_mcontext.eip; // EIP: x86 specific
#elif defined(__x86_64__) // gcc specific
 caller_address = (void *) uc->uc_mcontext.rip; // RIP: x86_64 specific
#else
#error Unsupported architecture. // TODO: Add support for other arch.
#endif

 fprintf(stderr, "signal %d (%s), address is %p from %p\n", 
  sig_num, strsignal(sig_num), info->si_addr, 
  (void *)caller_address);

 size = backtrace(array, 50);

 /* overwrite sigaction with caller's address */
 array[1] = caller_address;

 messages = backtrace_symbols(array, size);

 /* skip first stack frame (points here) */
 for (i = 1; i < size && messages != NULL; ++i)
 {
  fprintf(stderr, "[bt]: (%d) %s\n", i, messages[i]);
 }

 free(messages);

 exit(EXIT_FAILURE);
}

int crash()
{
 char * p = NULL;
 *p = 0;
 return 0;
}

int foo4()
{
 crash();
 return 0;
}

int foo3()
{
 foo4();
 return 0;
}

int foo2()
{
 foo3();
 return 0;
}

int foo1()
{
 foo2();
 return 0;
}

int main(int argc, char ** argv)
{
 struct sigaction sigact;

 sigact.sa_sigaction = crit_err_hdlr;
 sigact.sa_flags = SA_RESTART | SA_SIGINFO;

 if (sigaction(SIGSEGV, &sigact, (struct sigaction *)NULL) != 0)
 {
  fprintf(stderr, "error setting signal handler for %d (%s)\n",
    SIGSEGV, strsignal(SIGSEGV));

  exit(EXIT_FAILURE);
 }

 foo1();

 exit(EXIT_SUCCESS);
}

Выход

signal 11 (Segmentation fault), address is (nil) from 0x8c50
[bt]: (1) ./test(crash+0x24) [0x8c50]
[bt]: (2) ./test(foo4+0x10) [0x8c70]
[bt]: (3) ./test(foo3+0x10) [0x8c8c]
[bt]: (4) ./test(foo2+0x10) [0x8ca8]
[bt]: (5) ./test(foo1+0x10) [0x8cc4]
[bt]: (6) ./test(main+0x74) [0x8d44]
[bt]: (7) /lib/libc.so.6(__libc_start_main+0xa8) [0x40032e44]

Все опасности вызова функций backtrace () в обработчике сигналов все еще существуют и не следует упускать из виду, но я считаю, что описанные здесь функциональные возможности весьма полезны при отладке сбоев.

Важно отметить, что приведенный мной пример разработан / протестирован в Linux для x86. Я также успешно реализовал это в ARM, используя uc_mcontext.arm_pc вместо uc_mcontext.eip .

Вот ссылка на статью, в которой я узнал подробности этой реализации: http://www.linuxjournal.com/article/6391

118
ответ дан 22 November 2019 в 22:13
поделиться

Хотя был предоставлен правильный ответ , который описывает, как использовать GNU libc backtrace () функцию 1 , и я предоставил свой собственный ответ , который описывает, как гарантировать, что обратная трассировка от обработчика сигнала указывает на фактическое местоположение неисправности 2 , я не вижу никаких упоминаний о разметке символов C ++, выводимых из след.

При получении трассировки из программы на C ++ вывод можно запустить через c ++ filter 1 , чтобы распутать символы, или с помощью abi :: __ cxa_demangle 1 напрямую.

  • 1 Linux и OS X Обратите внимание, что c ++ filter и __ cxa_demangle относятся к GCC
  • 2 Linux

В следующем примере C ++ Linux используется тот же обработчик сигнала, что и в моем другом ответе , и демонстрируется, как c ++ filter можно использовать для распутывания символов.

Код :

class foo
{
public:
    foo() { foo1(); }

private:
    void foo1() { foo2(); }
    void foo2() { foo3(); }
    void foo3() { foo4(); }
    void foo4() { crash(); }
    void crash() { char * p = NULL; *p = 0; }
};

int main(int argc, char ** argv)
{
    // Setup signal handler for SIGSEGV
    ...

    foo * f = new foo();
    return 0;
}

Вывод ( ./ test ):

signal 11 (Segmentation fault), address is (nil) from 0x8048e07
[bt]: (1) ./test(crash__3foo+0x13) [0x8048e07]
[bt]: (2) ./test(foo4__3foo+0x12) [0x8048dee]
[bt]: (3) ./test(foo3__3foo+0x12) [0x8048dd6]
[bt]: (4) ./test(foo2__3foo+0x12) [0x8048dbe]
[bt]: (5) ./test(foo1__3foo+0x12) [0x8048da6]
[bt]: (6) ./test(__3foo+0x12) [0x8048d8e]
[bt]: (7) ./test(main+0xe0) [0x8048d18]
[bt]: (8) ./test(__libc_start_main+0x95) [0x42017589]
[bt]: (9) ./test(__register_frame_info+0x3d) [0x8048981]

Вывод без запутывания ( ./ test 2> & 1 | c ++ filter ):

signal 11 (Segmentation fault), address is (nil) from 0x8048e07
[bt]: (1) ./test(foo::crash(void)+0x13) [0x8048e07]
[bt]: (2) ./test(foo::foo4(void)+0x12) [0x8048dee]
[bt]: (3) ./test(foo::foo3(void)+0x12) [0x8048dd6]
[bt]: (4) ./test(foo::foo2(void)+0x12) [0x8048dbe]
[bt]: (5) ./test(foo::foo1(void)+0x12) [0x8048da6]
[bt]: (6) ./test(foo::foo(void)+0x12) [0x8048d8e]
[bt]: (7) ./test(main+0xe0) [0x8048d18]
[bt]: (8) ./test(__libc_start_main+0x95) [0x42017589]
[bt]: (9) ./test(__register_frame_info+0x3d) [0x8048981]

Следующее построено на обработчике сигнала из моего исходного ответа и может заменить обработчик сигнала в приведенном выше примере, чтобы продемонстрировать, как abi :: __ cxa_demangle может быть используется для распутывания символов. Этот обработчик сигнала производит такой же разобранный вывод, что и в приведенном выше примере.

Код :

void crit_err_hdlr(int sig_num, siginfo_t * info, void * ucontext)
{
    sig_ucontext_t * uc = (sig_ucontext_t *)ucontext;

    void * caller_address = (void *) uc->uc_mcontext.eip; // x86 specific

    std::cerr << "signal " << sig_num 
              << " (" << strsignal(sig_num) << "), address is " 
              << info->si_addr << " from " << caller_address 
              << std::endl << std::endl;

    void * array[50];
    int size = backtrace(array, 50);

    array[1] = caller_address;

    char ** messages = backtrace_symbols(array, size);    

    // skip first stack frame (points here)
    for (int i = 1; i < size && messages != NULL; ++i)
    {
        char *mangled_name = 0, *offset_begin = 0, *offset_end = 0;

        // find parantheses and +address offset surrounding mangled name
        for (char *p = messages[i]; *p; ++p)
        {
            if (*p == '(') 
            {
                mangled_name = p; 
            }
            else if (*p == '+') 
            {
                offset_begin = p;
            }
            else if (*p == ')')
            {
                offset_end = p;
                break;
            }
        }

        // if the line could be processed, attempt to demangle the symbol
        if (mangled_name && offset_begin && offset_end && 
            mangled_name < offset_begin)
        {
            *mangled_name++ = '\0';
            *offset_begin++ = '\0';
            *offset_end++ = '\0';

            int status;
            char * real_name = abi::__cxa_demangle(mangled_name, 0, 0, &status);

            // if demangling is successful, output the demangled function name
            if (status == 0)
            {    
                std::cerr << "[bt]: (" << i << ") " << messages[i] << " : " 
                          << real_name << "+" << offset_begin << offset_end 
                          << std::endl;

            }
            // otherwise, output the mangled function name
            else
            {
                std::cerr << "[bt]: (" << i << ") " << messages[i] << " : " 
                          << mangled_name << "+" << offset_begin << offset_end 
                          << std::endl;
            }
            free(real_name);
        }
        // otherwise, print the whole line
        else
        {
            std::cerr << "[bt]: (" << i << ") " << messages[i] << std::endl;
        }
    }
    std::cerr << std::endl;

    free(messages);

    exit(EXIT_FAILURE);
}
81
ответ дан 22 November 2019 в 22:13
поделиться
Другие вопросы по тегам:

Похожие вопросы: