যখন আমার প্রোগ্রামটি ক্র্যাশ হবে তখন কীভাবে স্বয়ংক্রিয়ভাবে একটি স্ট্যাকট্র্যাস তৈরি করা যায়


590

আমি জিসিসি সংকলক সহ লিনাক্সে কাজ করছি। আমার সি ++ প্রোগ্রামটি ক্র্যাশ হয়ে গেলে আমি এটি স্বয়ংক্রিয়ভাবে স্ট্যাকট্রেস তৈরি করতে চাই।

আমার প্রোগ্রামটি অনেকগুলি বিভিন্ন ব্যবহারকারী দ্বারা চালিত হচ্ছে এবং এটি লিনাক্স, উইন্ডোজ এবং ম্যাকিনটোস-এও চালিত হয় (সমস্ত সংস্করণ ব্যবহার করে সংকলিত হয় gcc)।

আমি চাই যে আমার প্রোগ্রামটি ক্র্যাশ হওয়ার সাথে সাথে একটি স্ট্যাক ট্রেস তৈরি করতে সক্ষম হবে এবং পরের বার যখন ব্যবহারকারী এটি চালাবে, তখন তাদের জিজ্ঞাসা করা হবে যে স্ট্যাকের ট্রেসটি আমার কাছে প্রেরণ করা ঠিক আছে যাতে আমি সমস্যাটি সন্ধান করতে পারি। আমি আমার কাছে প্রেরণ সম্পর্কিত তথ্যটি পরিচালনা করতে পারি তবে কীভাবে ট্রেস স্ট্রিং তৈরি করতে হয় তা আমি জানি না। কোন ধারনা?


4
backtrace এবং backtrace_symbols_fd অ্যাসিঙ্ক-সিগন্যাল-নিরাপদ নয়। আপনার এই ফাংশনটি সিগন্যাল হ্যান্ডলারটিতে ব্যবহার করা উচিত নয়
পরাগ বাফনা

10
backtrace_symbols কল করে malloc, এবং তাই একটি সংকেত হ্যান্ডলার ব্যবহার করা উচিত হবে না। অন্য দুটি ফাংশন (ব্যাকট্র্যাস এবং ব্যাকট্র্যাস_সাইক্লবস_ফডি) এর সমস্যা নেই এবং এটি সাধারণত সিগন্যাল হ্যান্ডলারে ব্যবহৃত হয়।
সেএমসিবিবে

3
@ সিএমসিসিবি যা ভুল ব্যাকট্র্যাস_সাইমবুলস_ফডি হয় সাধারণত ম্যালোককে কল করে না তবে যদি তার ক্যাচ_অররর ব্লকে কিছু ভুল হয়ে যায়
স্যাম

6
এটি "এই" অর্থে যে "ব্যাকট্রেস_সাইম্বলস_ফডি (বা কোনও ব্যাকট্র্যাস) এর জন্য কোনও পসিক্স অনুমান নেই; তবে, জিএনইউ / লিনাক্সের ব্যাকট্রেস_সাইম্বলস_ফডি লিনাক্স.ডিয়েইনট / ম্যান / ৩ / বিট্রেস_সাইম্বলস_ফডি অনুসারে কখনও ম্যালোক কল করতে নির্দিষ্ট করা হয়নি । সুতরাং এটি ধরে নেওয়া নিরাপদ যে এটি লিনাক্সে কখনও ম্যালোক কল করবে না।
কোডেটাকু

কিভাবে এটি ক্রাশ হয়?
সিরো সান্তিলি 郝海东 冠状 病 六四 事件 法轮功

উত্তর:


509

লিনাক্স এবং আমি বিশ্বাস করি ম্যাক ওএস এক্স এর জন্য, আপনি যদি জিসিসি, বা কোনও গ্লিবসি ব্যবহার করে এমন কোনও সংকলক ব্যবহার করেন, আপনি execinfo.hস্ট্যাকট্রেস প্রিন্ট করতে ব্যাকট্রেস () ফাংশনগুলি ব্যবহার করতে পারেন এবং যখন আপনি কোনও সেগমেন্টেশন ত্রুটি পেয়ে যাবেন তখন আপনি মনোযোগ দিয়ে প্রস্থান করতে পারেন। লিবিসি ম্যানুয়ালটিতে ডকুমেন্টেশন পাওয়া যায় ।

এখানে একটি উদাহরণ প্রোগ্রাম রয়েছে যা একটি SIGSEGVহ্যান্ডলার ইনস্টল করে এবং stderrযখন সেগফল্ট হয় তখন স্ট্যাকট্রেস প্রিন্ট করে। এখানে baz()ফাংশনটি সেগফল্টের কারণ হ্যান্ডলারটিকে ট্রিগার করে:

#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আপনার আউটপুটে আপনাকে প্রতীকী তথ্য দিয়ে সংকলন করা হয় , যা গ্লিবসি একটি দুর্দান্ত স্ট্যাকট্রেস তৈরি করতে ব্যবহার করতে পারে:

$ 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


53
এখানে /lib/libSegFault.so রয়েছে যা আপনি LD_PRELOAD এর সাথে ব্যবহার করতে পারেন।
সিজারবি

6
দেখে মনে হচ্ছে আপনার ব্যাকট্রেস আউটপুটে প্রথম দুটি এন্ট্রিগুলিতে সিগন্যাল হ্যান্ডলারের ভিতরে একটি রিটার্ন ঠিকানা এবং সম্ভবত একটি sigaction()লিবিসি রয়েছে। আপনার ব্যাকট্রেসটি সঠিক বলে মনে হচ্ছে, তবুও আমি মাঝে মাঝে খুঁজে পেয়েছি যে ত্রুটির প্রকৃত অবস্থান ব্যাকট্রেসে প্রদর্শিত হবে তা নিশ্চিত করার জন্য অতিরিক্ত পদক্ষেপগুলি প্রয়োজনীয় কারণ এটি sigaction()কার্নেলের সাহায্যে ওভাররাইট করা যেতে পারে ।
jschmier

9
ক্র্যাশটি যদি ম্যালোকের ভিতরে থেকে আসে তবে কী হবে? "ব্যাকট্রেস" মেমরি বরাদ্দ করার চেষ্টা করার পরে আপনি কি কোনও লক ধরে ধরে আটকে যাবেন না?
ম্যাটিয়াস নীলসন

7
catchsegvওপি যা প্রয়োজন তা নয় তবে বিভাগীয় ত্রুটিগুলি ধরা এবং সমস্ত তথ্য পাওয়ার জন্য দুর্দান্ত।
ম্যাট ক্লার্কসন 10

8
এআরএমের জন্য, আমাকে -funwind- টেবিলগুলিও সংকলন করতে হয়েছিল। অন্যথায় আমার স্ট্যাকের গভীরতা সর্বদা 1 (খালি) ছিল।
jfritz42

128

এটি "ম্যান ব্যাকট্রেস" এর চেয়েও সহজ, এখানে একটি সামান্য-ডকুমেন্টেড লাইব্রেরি (জিএনইউ সুনির্দিষ্ট) লাইবসেগফোল্ট.স হিসাবে গ্লিব্যাক দিয়ে বিতরণ করা হয়েছিল, যা আমি বিশ্বাস করি যে এই প্রোগ্রাম ক্যাচসেগভকে সমর্থন করার জন্য উলরিচ ড্রিপার লিখেছিলেন ("ম্যান ক্যাচসেগভি" দেখুন)।

এটি আমাদের 3 সম্ভাবনা দেয়। "প্রোগ্রাম -o হাই" চালানোর পরিবর্তে:

  1. ক্যাচসেগভের মধ্যে চালান:

    $ catchsegv program -o hai
  2. রানটাইমের সময় libSegFault এর সাথে লিঙ্ক করুন:

    $ LD_PRELOAD=/lib/libSegFault.so program -o hai
  3. সংকলনের সময় libSegFault এর সাথে লিঙ্ক করুন:

    $ gcc -g1 -lSegFault -o program program.cc
    $ program -o hai
    

সমস্ত 3 ক্ষেত্রে, আপনি কম অপ্টিমাইজেশনের (জিসিসি -O0 বা -O1) এবং ডিবাগিং প্রতীক (জিসিসি-জি) সহ পরিষ্কার ব্যাকট্রেস পাবেন। অন্যথায়, আপনি কেবল মেমরি ঠিকানাগুলির একটি গাদা দিয়ে শেষ করতে পারেন।

আপনি স্ট্যাকের চিহ্নগুলির জন্য আরও কিছু সংকেত ধরতে পারেন যেমন:

$ export SEGFAULT_SIGNALS="all"       # "all" signals
$ export SEGFAULT_SIGNALS="bus abrt"  # SIGBUS and SIGABRT

আউটপুটটি এরকম কিছু দেখাচ্ছে (নীচে ব্যাকট্রিজটি লক্ষ্য করুন):

*** Segmentation fault Register dump:

 EAX: 0000000c   EBX: 00000080   ECX:
00000000   EDX: 0000000c  ESI:
bfdbf080   EDI: 080497e0   EBP:
bfdbee38   ESP: bfdbee20

 EIP: 0805640f   EFLAGS: 00010282

 CS: 0073   DS: 007b   ES: 007b   FS:
0000   GS: 0033   SS: 007b

 Trap: 0000000e   Error: 00000004  
OldMask: 00000000  ESP/signal:
bfdbee20   CR2: 00000024

 FPUCW: ffff037f   FPUSW: ffff0000  
TAG: ffffffff  IPOFF: 00000000  
CSSEL: 0000   DATAOFF: 00000000  
DATASEL: 0000

 ST(0) 0000 0000000000000000   ST(1)
0000 0000000000000000  ST(2) 0000
0000000000000000   ST(3) 0000
0000000000000000  ST(4) 0000
0000000000000000   ST(5) 0000
0000000000000000  ST(6) 0000
0000000000000000   ST(7) 0000
0000000000000000

Backtrace:
/lib/libSegFault.so[0xb7f9e100]
??:0(??)[0xb7fa3400]
/usr/include/c++/4.3/bits/stl_queue.h:226(_ZNSt5queueISsSt5dequeISsSaISsEEE4pushERKSs)[0x805647a]
/home/dbingham/src/middle-earth-mud/alpha6/src/engine/player.cpp:73(_ZN6Player5inputESs)[0x805377c]
/home/dbingham/src/middle-earth-mud/alpha6/src/engine/socket.cpp:159(_ZN6Socket4ReadEv)[0x8050698]
/home/dbingham/src/middle-earth-mud/alpha6/src/engine/socket.cpp:413(_ZN12ServerSocket4ReadEv)[0x80507ad]
/home/dbingham/src/middle-earth-mud/alpha6/src/engine/socket.cpp:300(_ZN12ServerSocket4pollEv)[0x8050b44]
/home/dbingham/src/middle-earth-mud/alpha6/src/engine/main.cpp:34(main)[0x8049a72]
/lib/tls/i686/cmov/libc.so.6(__libc_start_main+0xe5)[0xb7d1b775]
/build/buildd/glibc-2.9/csu/../sysdeps/i386/elf/start.S:122(_start)[0x8049801]

আপনি যদি বিব্রত বিশদটি জানতে চান তবে সেরা উত্সটি দুর্ভাগ্যক্রমে উত্স: দেখুন http://sourceware.org/git/?p=glibc.git ;a=blob ;f=debug/ segfault.c এবং এর মূল ডিরেক্টরিটি http://sourceware.org/git/?p=glibc.git;a=tree;f=debug


1
"সম্ভাব্যতা 3. সংকলনের সময় libegFault সাথে লিঙ্ক" কাজ করে না।
এইচএইচকে

5
@ ক্রাফটার: আপনার অর্থ "কাজ করে না"। কোন ভাষা / সংকলক / সরঞ্জামচইন / বিতরণ / হার্ডওয়্যার আপনি কী চেষ্টা করেছেন? এটি সংকলন করতে ব্যর্থ হয়েছে? ত্রুটি ধরতে? আদৌ আউটপুট উত্পাদন করতে? হার্ড-টু-ব্যবহার আউটপুট উত্পাদন করতে? এটি প্রত্যেককে সহায়তা করবে বিশদগুলির জন্য আপনাকে ধন্যবাদ।
স্টাফেন গৌরিচন

1
'সেরা উত্স দুর্ভাগ্যক্রমে উত্স' ... আশা করি, কোনও দিন, ক্যাচসেকভের ম্যান পেজটি SEGFAULT_SIGNALS উল্লেখ করবে N ততক্ষণ, এখানে এই জবাবটি উল্লেখ করা আছে।
গ্রেগগো

আমি বিশ্বাস করতে পারি না যে আমি 5 বছর ধরে সি প্রোগ্রামিং করছি এবং এর আগে কখনও শুনিনি: /
ডেভিডএমফ্রে

6
@ স্টাফেনগৌরিচন @ হ্যানস ক্যাটজ লাইবসেজফোল্টের সাথে লিঙ্ক করতে আপনাকে -Wl,--no-as-neededসংকলক পতাকাগুলি যুক্ত করতে হবে। অন্যথায়, ldপ্রকৃতপক্ষে লিঙ্ক করবে নাlibSegFault , কারণ এটি স্বীকৃতি দেয় যে বাইনারি তার কোনও চিহ্ন ব্যবহার করে না।
ফিলিপ

122

লিনাক্স

যখন আপনি একটি খণ্ডিত ত্রুটি ইতিমধ্যে প্রস্তাব পেয়েছেন তখন একটি স্ট্যাকট্রেস মুদ্রণ করতে এবং দক্ষতার সাথে প্রস্থান করার জন্য এক্সাইনিনফোতে ব্যাকট্রেস () ফাংশনগুলির ব্যবহারের পরামর্শ দেওয়া হয়েছে , ফলস্বরূপ ব্যাকট্রেস পয়েন্টগুলি প্রকৃত অবস্থানের জন্য নিশ্চিত করার জন্য প্রয়োজনীয় জটিলতার কোনও উল্লেখ আমি দেখতে পাই না দোষ (কমপক্ষে কিছু স্থাপত্যের জন্য - x86 এবং এআরএম)

আপনি যখন সিগন্যাল হ্যান্ডলারের সাথে উঠবেন তখন স্ট্যাক ফ্রেম চেইনে প্রথম দুটি এন্ট্রিগুলিতে সিগন্যাল হ্যান্ডলারের অভ্যন্তরে একটি রিটার্ন ঠিকানা এবং একটি লাইব্যাকের মধ্যে সিগিয়েশন () এর মধ্যে একটি থাকে। শেষ ফাংশনটির স্ট্যাক ফ্রেমটি সিগন্যালের (যা ত্রুটির অবস্থান) হারিয়ে যাওয়ার আগে ডেকে আনে।

কোড

#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]

সিগন্যাল হ্যান্ডলারের ব্যাকট্রেস () ফাংশনগুলিতে কল করার সমস্ত বিপদগুলি এখনও রয়েছে এবং এটি উপেক্ষা করা উচিত নয়, তবে আমি এখানে বর্ণিত ক্রিয়াকলাপটিকে ক্র্যাশগুলি ডিবাগ করতে বেশ সহায়ক বলে মনে করি।

এটি লক্ষণীয় গুরুত্বপূর্ণ যে আমি প্রদত্ত উদাহরণটি x86 এর জন্য লিনাক্সে বিকাশ / পরীক্ষিত। আমি এটির uc_mcontext.arm_pcপরিবর্তে এটিআরএম এ সফলভাবে প্রয়োগ করেছি uc_mcontext.eip

: এখানে নিবন্ধ যেখানে আমি এই বাস্তবায়নের বিস্তারিত শিখেছি একটি লিঙ্ক আছে http://www.linuxjournal.com/article/6391


11
জিএনইউ এলডি ব্যবহার করে এমন সিস্টেমে -rdynamicলিঙ্কারকে গতিশীল প্রতীক টেবিলটিতে কেবল ব্যবহৃত ব্যবহৃত নয়, সমস্ত প্রতীক যুক্ত করার নির্দেশ দিয়ে সংকলন করতে ভুলবেন না। এটি backtrace_symbols()ঠিকানাগুলিকে ফাংশন নামে রূপান্তর করতে দেয়
jschmier ২er

1
এছাড়াও, আপনাকে এআরএম প্ল্যাটফর্মে স্ট্যাক ফ্রেম তৈরি করতে জিসিসি'র কমান্ড লাইনে "-mapcs-ফ্রেম" বিকল্পটি যুক্ত করতে হবে
qehgt

3
এটি অনেক দেরিতে হতে পারে তবে addr2lineক্র্যাশটি ঘটেছিল যেখানে সঠিক লাইনটি পেতে আমরা কোনওভাবে কমান্ড ব্যবহার করতে পারি ?
উত্সাহী

4
আরও সাম্প্রতিক বিল্ডগুলিতে glibc uc_mcontextএকটি ক্ষেত্র নেই eip। এখন একটি অ্যারে রয়েছে যা সূচকের প্রয়োজন, uc_mcontext.gregs[REG_EIP]সমতুল্য।
এমএমএলবি

6
এআরএম-এর জন্য, আমার ব্যাকট্রেসগুলির সর্বদা গভীরতা 1 ছিল যতক্ষণ না আমি সংযোজকটিতে -Funwind- টেবিল বিকল্প যুক্ত করি।
jfritz42

84

যদিও সঠিক উত্তর সরবরাহ করা হয়েছে যা GNU libc backtrace()ফাংশন 1 কীভাবে ব্যবহার করতে হবে তা বর্ণনা করে এবং আমি আমার নিজস্ব উত্তর সরবরাহ করেছি যা কীভাবে সিগন্যাল হ্যান্ডলার থেকে ব্যাকট্রিজটি নিশ্চিত করতে হবে তা দোষ 2 এর প্রকৃত অবস্থানের দিকে নির্দেশ করে , আমি দেখতে পাই না ব্যাকট্রেস থেকে সি ++ প্রতীক আউটপুট ডিমেংলিংয়ের কোনও উল্লেখ ।

যখন একটি সি ++ প্রোগ্রাম থেকে ব্যাক প্রাপ্তির, আউটপুট মাধ্যমে চালানো যাবে c++filt1 প্রতীক demangle অথবা ব্যবহার করে 1 সরাসরি।abi::__cxa_demangle

  • 1 লিনাক্স এবং ওএস এক্স নোট করুন c++filtএবং __cxa_demangleএটি জিসিসি নির্দিষ্ট
  • 2 লিনাক্স

নিম্নলিখিত সি ++ লিনাক্স উদাহরণটি আমার অন্যান্য উত্তরের মতো একই সংকেত হ্যান্ডলারটি ব্যবহার করে এবং দেখায় যে কীভাবে c++filtপ্রতীকগুলি ডিমেংল করতে ব্যবহার করা যেতে পারে।

কোড :

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++filt):

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);
}

1
জেসমিয়ার এর জন্য আপনাকে ধন্যবাদ। আমি এর আউটপুটটিকে অ্যাডার 2লাইন ইউটিলিটিতে ফিড করতে একটি সামান্য বাশ স্ক্রিপ্ট তৈরি করেছি। দেখুন:
stackoverflow.com/a/15801966/1797414

4
# অন্তর্ভুক্ত <সিএক্সএক্সবি.এস>> ভুলে যাবেন না
বামাকো

1
ভাল ডকুমেন্টেশন, এবং একটি সরল হেডার ফাইল ২০০৮ সাল থেকে এখানে পোস্ট করা হয়েছে ... panthema.net/2008/0901-stacktrace-demangled আপনার পদ্ধতির সাথে খুব মিল) :)
কেভিনফ

abi :: __ cxa_demangle async- সিগন্যাল-নিরাপদ বলে মনে হচ্ছে না, তাই সিগন্যাল হ্যান্ডলারটি malloc এ কোথাও অচলাবস্থা রাখতে পারে।
অরিসি

ব্যবহারের std::cerr, free()এবং exit()সব POSIX সিস্টেমে অ ASYNC-সংকেত-নিরাপদ কল কলিং বিরুদ্ধে নিষেধাজ্ঞা লঙ্ঘন করে। , বা , যেমন কোনও কলটিতে আপনার প্রক্রিয়া ব্যর্থ হলে এই কোডটি অচল হবে । free()malloc() newdetete
অ্যান্ড্রু হেনেল

31

এ খুঁজছেন মূল্য হতে পারে গুগল Breakpad , একটি ক্রস-প্ল্যাটফর্ম ক্র্যাশ ডাম্প জেনারেটর এবং ডাম্প প্রক্রিয়া সরঞ্জাম।


এটি বিভাগের ত্রুটিগুলির মতো স্টাফগুলিতে রিপোর্ট করে তবে এটি হ্যান্ডেলড সি ++ ব্যতিক্রম সম্পর্কিত কোনও তথ্যের প্রতিবেদন করে না।
DBedrenko

21

আপনি আপনার অপারেটিং সিস্টেমটি নির্দিষ্ট করেন নি, সুতরাং উত্তর দেওয়া এটি কঠিন। যদি আপনি gnu libc ভিত্তিক একটি সিস্টেম ব্যবহার করেন তবে আপনি libc ফাংশনটি ব্যবহার করতে সক্ষম হতে পারেন backtrace()

জিসিসির দুটি বিল্টিন রয়েছে যা আপনাকে সহায়তা করতে পারে, তবে যা আপনার আর্কিটেকচারে পুরোপুরি প্রয়োগ করা হতে পারে এবং নাও হতে পারে এবং সেগুলি হয় __builtin_frame_addressএবং __builtin_return_address। উভয়ই একটি তাত্ক্ষণিক পূর্ণসংখ্যার স্তর চায় (তাত্ক্ষণিকভাবে, আমি বোঝাতে চাইছি এটি একটি পরিবর্তনশীল হতে পারে না)। যদি __builtin_frame_addressকোনও প্রদত্ত স্তরের জন্য শূন্য হয় না তবে একই স্তরের ফেরতের ঠিকানাটি ধরা নিরাপদ হওয়া উচিত।


13

অ্যাডর 2 লাইন ইউটিলিটিতে আমার দৃষ্টি আকর্ষণ করার জন্য উত্সাহী ধন্যবাদ জানাতে ধন্যবাদ।

আমি এখানে সরবরাহ করা উত্তরের আউটপুট প্রক্রিয়া করতে একটি দ্রুত এবং নোংরা স্ক্রিপ্ট লিখেছি :

স্ক্রিপ্টটি একটি একক আর্গুমেন্ট গ্রহণ করে: jschmier এর ইউটিলিটি থেকে আউটপুট যুক্ত ফাইলের নাম।

আউটপুটটিতে ট্রেসের প্রতিটি স্তরের জন্য নীচের মতো কিছু মুদ্রণ করা উচিত:

BACKTRACE:  testExe 0x8A5db6b
FILE:       pathToFile/testExe.C:110
FUNCTION:   testFunction(int) 
   107  
   108           
   109           int* i = 0x0;
  *110           *i = 5;
   111      
   112        }
   113        return i;

কোড:

#!/bin/bash

LOGFILE=$1

NUM_SRC_CONTEXT_LINES=3

old_IFS=$IFS  # save the field separator           
IFS=$'\n'     # new field separator, the end of line           

for bt in `cat $LOGFILE | grep '\[bt\]'`; do
   IFS=$old_IFS     # restore default field separator 
   printf '\n'
   EXEC=`echo $bt | cut -d' ' -f3 | cut -d'(' -f1`  
   ADDR=`echo $bt | cut -d'[' -f3 | cut -d']' -f1`
   echo "BACKTRACE:  $EXEC $ADDR"
   A2L=`addr2line -a $ADDR -e $EXEC -pfC`
   #echo "A2L:        $A2L"

   FUNCTION=`echo $A2L | sed 's/\<at\>.*//' | cut -d' ' -f2-99`
   FILE_AND_LINE=`echo $A2L | sed 's/.* at //'`
   echo "FILE:       $FILE_AND_LINE"
   echo "FUNCTION:   $FUNCTION"

   # print offending source code
   SRCFILE=`echo $FILE_AND_LINE | cut -d':' -f1`
   LINENUM=`echo $FILE_AND_LINE | cut -d':' -f2`
   if ([ -f $SRCFILE ]); then
      cat -n $SRCFILE | grep -C $NUM_SRC_CONTEXT_LINES "^ *$LINENUM\>" | sed "s/ $LINENUM/*$LINENUM/"
   else
      echo "File not found: $SRCFILE"
   fi
   IFS=$'\n'     # new field separator, the end of line           
done

IFS=$old_IFS     # restore default field separator 

12

ulimit -c <value>ইউনিক্সে মূল ফাইলের আকার সীমা নির্ধারণ করে। ডিফল্টরূপে, কোর ফাইলের আকার সীমা 0. আপনি আপনার দেখতে পারেন ulimitসঙ্গে মান ulimit -a

এছাড়াও, আপনি যদি জিডিবি এর মধ্যে থেকে আপনার প্রোগ্রামটি চালনা করেন তবে এটি "বিভাজন লঙ্ঘন" (আপনার SIGSEGVসাধারণত বরাদ্দ না করা মেমরির কোনও অংশ অ্যাক্সেস করলে) বা আপনার ব্রেকপয়েন্ট সেট করতে পারে আপনার প্রোগ্রামটি থামিয়ে দেবে ।

ডিডিডি এবং নেমাইভার হ'ল জিডিবি-র ফ্রন্ট-এ্যান্ডস যা এতে কাজ করে নবজাতকের পক্ষে আরও সহজ করে তোলে।


6
স্টোর ট্রেসের চেয়ে কোর ডাম্পগুলি সীমাহীনভাবে বেশি কার্যকর কারণ আপনি ডিবাগারে কোর ডাম্প লোড করতে পারেন এবং ক্র্যাশ হওয়ার সময় পুরো প্রোগ্রাম এবং এর ডেটা দেখতে পারেন।
অ্যাডাম হাউস

1
অন্যরা যে ব্যাকট্রেস সুবিধাটি বলেছে সেগুলি সম্ভবত কোনও কিছুর চেয়ে ভাল তবে এটি খুব মৌলিক - এটি লাইন নম্বরও দেয় না। অন্যদিকে, কোর ডাম্পগুলি ব্যবহার করে, ক্র্যাশ হওয়ার সময় আপনার অ্যাপ্লিকেশনটির পুরো রাজ্যটি পূর্ববর্তীভাবে দেখতে দিন (বিস্তারিত স্ট্যাক ট্রেস সহ)। সেখানে পারে ক্ষেত্র ডিবাগিং করার জন্য এই ব্যবহার করার চেষ্টা সঙ্গে ব্যবহারিক বিষয় হতে, কিন্তু এটা স্পষ্টভাবে বিশ্লেষণ বিপর্যের জন্য একটি অধিক শক্তিশালী টুল এবং (অন্তত লিনাক্স দিকে) উন্নয়ন সময় দাবি।
nobar

10

এটি লক্ষণীয় গুরুত্বপূর্ণ যে আপনি একবার একটি মূল ফাইল তৈরি করলে আপনার এটি দেখতে জিডিবি সরঞ্জামটি ব্যবহার করতে হবে। আপনার মূল ফাইলটি বোঝার জন্য জিডিবি-র জন্য, আপনাকে অবশ্যই জিসিসি-কে ডিবাগিং প্রতীক সহ বাইনারিটি ইনস্ট্রুম করতে বলতে হবে: এটি করতে, আপনি -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 ...

আশা করি এটা কাজে লাগবে.


4
আপনি gdbআপনার ক্র্যাশিং প্রোগ্রাম থেকে সরাসরি কল করতে পারেন । জিএসডিবি কল করবে SIGSEGV, SEGILL, SIGBUS, SIGFPE এর জন্য সেটআপ হ্যান্ডলার। বিশদ: স্ট্যাকওভারফ্লো / সেকশনস / ৩১১7917/79 / / The সুবিধাটি হ'ল আপনি সুন্দর, এনোটেটেড ব্যাকট্রিস এর মতো পেয়েছেন bt fullএবং আপনি সমস্ত থ্রেডের স্ট্যাক ট্রেসগুলি পেতে পারেন।
vi।

উত্তরের চেয়ে আপনি ব্যাকট্রিসটি আরও সহজ পেতে পারেন: gdb -silent ./prog কোর --eval-কমান্ড = backtrace
ব্যাচ -এটি

10

আইভ কিছুক্ষণ ধরে এই সমস্যাটির দিকে তাকাচ্ছি।

এবং গুগল পারফরম্যান্স সরঞ্জামগুলি README তে গভীরভাবে কবর দেওয়া হয়েছে

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

libunwind সম্পর্কে আলোচনা

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

এই গ্রন্থাগারের মতামত শুনতে পছন্দ করবে।

-ডাইনামিকের সাথে সমস্যাটি হ'ল এটি কিছু ক্ষেত্রে বাইনারিটির আকার তুলনামূলকভাবে উল্লেখযোগ্যভাবে বাড়িয়ে তুলতে পারে


2
X86 / 64-তে, আমি বাইনারি আকারে -ডাইনামিক বৃদ্ধি দেখিনি। -G যোগ করা অনেক বড় বৃদ্ধি করে।
ড্যান

1
আমি লক্ষ্য করেছি যে লাইবুনউইন্ডের লাইন নম্বর পাওয়ার জন্য কার্যকারিতা নেই এবং আমি অনুমান করেছি (পরীক্ষা করা হয়নি) মূল নামের পরিবর্তে আনউইং_জেট_প্রোক_নামটি ফাংশন প্রতীকটি (যা ওভারলোডিং এবং এই জাতীয়ভাবে আবদ্ধ) ফিরিয়ে দেয়।
হারবার্ট

1
এটাই সঠিক. এটি সঠিকভাবে করা খুব জটিল হয়ে ওঠে, তবে আমি এখানে gaddr2line
গ্রেগরি

9

Libc এর কয়েকটি সংস্করণে এমন ফাংশন রয়েছে যা স্ট্যাকের চিহ্নগুলি নিয়ে কাজ করে; আপনি সেগুলি ব্যবহার করতে সক্ষম হতে পারেন:

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

আমার মনে আছে স্ট্যাক ট্রেসগুলি পেতে অনেক আগে লিবুনউইন্ড ব্যবহার করা হয়েছিল , তবে এটি আপনার প্ল্যাটফর্মে সমর্থিত নাও হতে পারে।


9

আপনি ডেথহ্যান্ডলার - ছোট সি ++ বর্গ ব্যবহার করতে পারেন যা আপনার জন্য নির্ভরযোগ্য, সব কিছু করে।


1
দুর্ভাগ্যক্রমে এটি execlp()অ্যাডার 2লাইন কলগুলি সম্পাদন করে ... নিজের প্রোগ্রামে পুরোপুরি থাকতে ভাল লাগবে (যা কিছু ফর্মে অ্যাডর 2 লাইন কোড যুক্ত করে সম্ভব)
উদাহরণস্বরূপ

9

আপনার উত্স পরিবর্তন সম্পর্কে ভুলে যান এবং ব্যাকট্র্যাস () ফাংশন বা ম্যাক্রোস দিয়ে কিছু হ্যাক করুন - এগুলি কেবল দুর্বল সমাধান।

সঠিকভাবে কাজ করার সমাধান হিসাবে, আমি পরামর্শ দেব:

  1. বাইনারিতে ডিবাগ প্রতীকগুলি এম্বেড করার জন্য "-g" পতাকাটি দিয়ে আপনার প্রোগ্রামটি সংকলন করুন (চিন্তা করবেন না এটি আপনার কার্যকারিতা প্রভাবিত করবে না))
  2. লিনাক্সে পরবর্তী কমান্ড চালান: "ulimit -c আনলিমিটেড" - - যাতে সিস্টেমকে বড় ক্রাশ ডাম্প তৈরি করতে দেয়।
  3. আপনার প্রোগ্রামটি ক্র্যাশ হয়ে গেলে, কার্যকারী ডিরেক্টরিতে আপনি "কোর" ফাইলটি দেখতে পাবেন।
  4. স্ট্যান্ডআউটে ব্যাকট্রেস প্রিন্ট করতে পরবর্তী কমান্ডটি চালান: gdb -batch -ex "backtrace" ./ আপনার_প্রগ্রাম_এক্স.কোরি

এটি মানব পাঠযোগ্য উপায়ে আপনার উত্সের যথাযথ পঠনযোগ্য ব্যাকট্রেস মুদ্রণ করবে (উত্স ফাইলের নাম এবং লাইন নম্বর সহ)। তদুপরি এই পদ্ধতির সাহায্যে আপনার সিস্টেমটি স্বয়ংক্রিয়করণের স্বাধীনতা পাওয়া যাবে: একটি শর্ট স্ক্রিপ্ট রয়েছে যা পরীক্ষা করে যদি প্রক্রিয়াটি একটি কোর ডাম্প তৈরি করে এবং তারপরে বিকাশকারীদের ইমেলের মাধ্যমে ব্যাকট্রেস প্রেরণ করে অথবা এটি কোনও লগিং সিস্টেমে লগইন করে।


এটি ভুল লাইন নম্বর দেয়। এটা কি উন্নতি করা যায়?
আরে জুড

7
ulimit -c unlimited

সিস্টেম ভেরিয়েবল, যা আপনার অ্যাপ্লিকেশন ক্রাশ হওয়ার পরে কোচ একটি ডাম্প তৈরি করার অনুমতি দেবে। এক্ষেত্রে সীমাহীন পরিমাণ। খুব একই ডিরেক্টরিতে কোর নামে একটি ফাইল সন্ধান করুন। নিশ্চিত করুন যে আপনি ডিবাগিং তথ্য সক্ষম সহ আপনার কোডটি সংকলন করেছেন!

শুভেচ্ছা


5
ব্যবহারকারী কোনও কোর ডাম্পের জন্য জিজ্ঞাসা করছেন না। তিনি একটি স্ট্যাক ট্রেস চাইছেন। Delorie.com/gnu/docs/glibc/libc_665.html
টড

1
একটি কোর ডাম্প ক্র্যাশের মুহুর্তে কল স্ট্যাক ধারণ করবে, তাই না?
মো।

3
আপনি ধরে নিচ্ছেন যে তিনি ইউনিক্সে আছেন এবং ব্যাশ ব্যবহার করছেন।
পল টমলিন

2
আপনি যদি limit coredumpsize unlimited
টিসিএস

6

তাকানো:

man 3 backtrace

এবং:

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

এগুলি হ'ল জিএনইউ এক্সটেনশন।


2
এই পৃষ্ঠায় সাহায্য করার জন্য আরও কিছু উদাহরণ থাকতে পারে যা আমি কিছুক্ষণ আগে তৈরি করেছি: charette.no-ip.com:81/pogramming/2010-01-25_Backtrace
স্টাফেন

6

ACE (ADAPTIVE যোগাযোগ পরিবেশ) এর স্ট্যাক ট্রেস সুবিধাটি দেখুন । এটি ইতিমধ্যে সমস্ত বড় প্ল্যাটফর্মগুলি (এবং আরও অনেকগুলি) কভার করার জন্য লেখা হয়েছে। লাইব্রেরিটি BSD- স্টাইলের লাইসেন্সযুক্ত তাই আপনি যদি এসি ব্যবহার করতে না চান তবে আপনি কোডটি অনুলিপি / পেস্ট করতে পারেন।


লিঙ্কটি মারা গেছে বলে মনে হচ্ছে।
tglas

5

আমি লিনাক্স সংস্করণে সহায়তা করতে পারি: ফাংশন ব্যাকট্র্যাস, ব্যাকট্র্যাস_সাইমবলস এবং ব্যাকট্র্যাস_সাইম্বলস_ফডি ব্যবহার করা যেতে পারে। সংশ্লিষ্ট ম্যানুয়াল পৃষ্ঠাগুলি দেখুন।


5

দেখে মনে হচ্ছে এটি গত সি ++ বুস্ট সংস্করণের একের মতো লাইব্রেরি হাজির যা আপনি যা চান ঠিক তা সরবরাহ করতে পারে, সম্ভবত কোডটি মাল্টিপ্লাটফর্ম হবে। এটি বুস্ট :: স্ট্যাকট্রেস যা আপনি বুস্ট নমুনার মতো ব্যবহার করতে পারেন :

#include <filesystem>
#include <sstream>
#include <fstream>
#include <signal.h>     // ::signal, ::raise
#include <boost/stacktrace.hpp>

const char* backtraceFileName = "./backtraceFile.dump";

void signalHandler(int)
{
    ::signal(SIGSEGV, SIG_DFL);
    ::signal(SIGABRT, SIG_DFL);
    boost::stacktrace::safe_dump_to(backtraceFileName);
    ::raise(SIGABRT);
}

void sendReport()
{
    if (std::filesystem::exists(backtraceFileName))
    {
        std::ifstream file(backtraceFileName);

        auto st = boost::stacktrace::stacktrace::from_dump(file);
        std::ostringstream backtraceStream;
        backtraceStream << st << std::endl;

        // sending the code from st

        file.close();
        std::filesystem::remove(backtraceFileName);
    }
}

int main()
{
    ::signal(SIGSEGV, signalHandler);
    ::signal(SIGABRT, signalHandler);

    sendReport();
    // ... rest of code
}

লিনাক্সে আপনি উপরের কোডটি সংকলন করুন:

g++ --std=c++17 file.cpp -lstdc++fs -lboost_stacktrace_backtrace -ldl -lbacktrace

বুস্ট ডকুমেন্টেশন থেকে অনুলিপি করা ব্যাকট্রিজ উদাহরণ :

0# bar(int) at /path/to/source/file.cpp:70
1# bar(int) at /path/to/source/file.cpp:70
2# bar(int) at /path/to/source/file.cpp:70
3# bar(int) at /path/to/source/file.cpp:70
4# main at /path/to/main.cpp:93
5# __libc_start_main in /lib/x86_64-linux-gnu/libc.so.6
6# _start

4

* নিক্স: আপনি SIGSEGV ( সাধারণত এই সংকেত ক্রাশ হওয়ার আগে উত্থাপিত হয়) আটকে রাখতে পারেন এবং তথ্যটি কোনও ফাইলে রেখে দিতে পারেন। (উদাহরণস্বরূপ জিডিবি ব্যবহার করে আপনি ডিবাগ করতে পারেন এমন মূল ফাইলটি ছাড়াও)।

win: চেক করুন এই MSDN থেকে।

গুগলের ক্রোম কোডটি ক্র্যাশগুলি কীভাবে পরিচালনা করে তা দেখতে আপনি এটিও দেখতে পারেন। এটিতে একটি দুর্দান্ত ব্যতিক্রম পরিচালনা ব্যবস্থা রয়েছে।


এসএইচ স্ট্যাক ট্রেস উত্পাদন করতে সহায়তা করে না। যদিও এটি কোনও সমাধানের অংশ হতে পারে, সেই সমাধানটি কার্যকর করা শক্ত এবং বাস্তব প্রয়োগের চেয়ে আপনার অ্যাপ্লিকেশন সম্পর্কে আরও তথ্য প্রকাশের ব্যয়ে কম তথ্য সরবরাহ করে : একটি মিনি ডাম্প লিখুন। এবং আপনার জন্য স্বয়ংক্রিয়ভাবে এটি করার জন্য উইন্ডোজ সেট আপ করুন।
IInspectable

4

আমি দেখেছি যে @tgamblin সমাধানটি সম্পূর্ণ নয়। এটি স্ট্যাকওভারফ্লো দিয়ে পরিচালনা করতে পারে না। আমি মনে করি কারণ ডিফল্টরূপে সিগন্যাল হ্যান্ডলারটি একই স্ট্যাকের সাথে ডাকা হয় এবং SIGSEGV দু'বার নিক্ষেপ করা হয়। সুরক্ষার জন্য আপনাকে সিগন্যাল হ্যান্ডলারের জন্য একটি স্বাধীন স্ট্যাক রেজিস্টার করতে হবে।

আপনি নীচের কোড সহ এটি চেক করতে পারেন। ডিফল্টরূপে হ্যান্ডলার ব্যর্থ হয়। সংজ্ঞায়িত ম্যাক্রো দিয়ে STACK_OVERFLOW ঠিক আছে।

#include <iostream>
#include <execinfo.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#include <string>
#include <cassert>

using namespace std;

//#define STACK_OVERFLOW

#ifdef STACK_OVERFLOW
static char stack_body[64*1024];
static stack_t sigseg_stack;
#endif

static struct sigaction sigseg_handler;

void handler(int sig) {
  cerr << "sig seg fault handler" << endl;
  const int asize = 10;
  void *array[asize];
  size_t size;

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

  // print out all the frames to stderr
  cerr << "stack trace: " << endl;
  backtrace_symbols_fd(array, size, STDERR_FILENO);
  cerr << "resend SIGSEGV to get core dump" << endl;
  signal(sig, SIG_DFL);
  kill(getpid(), sig);
}

void foo() {
  foo();
}

int main(int argc, char **argv) {
#ifdef STACK_OVERFLOW
  sigseg_stack.ss_sp = stack_body;
  sigseg_stack.ss_flags = SS_ONSTACK;
  sigseg_stack.ss_size = sizeof(stack_body);
  assert(!sigaltstack(&sigseg_stack, nullptr));
  sigseg_handler.sa_flags = SA_ONSTACK;
#else
  sigseg_handler.sa_flags = SA_RESTART;  
#endif
  sigseg_handler.sa_handler = &handler;
  assert(!sigaction(SIGSEGV, &sigseg_handler, nullptr));
  cout << "sig action set" << endl;
  foo();
  return 0;
} 

4

শহরে নতুন রাজা এসেছেন https://github.com/bombela/backward-cpp

আপনার কোডে 1 টি শিরোনাম এবং ইনস্টল করার জন্য 1 লাইব্রেরি।

ব্যক্তিগতভাবে আমি এই ফাংশনটি ব্যবহার করে এটি কল করি

#include "backward.hpp"
void stacker() {

using namespace backward;
StackTrace st;


st.load_here(99); //Limit the number of trace depth to 99
st.skip_n_firsts(3);//This will skip some backward internal function from the trace

Printer p;
p.snippet = true;
p.object = true;
p.color = true;
p.address = true;
p.print(st, stderr);
}

কি দারুন! শেষ পর্যন্ত কিভাবে এটি করা উচিত! আমি এইটির পক্ষে নিজের সমাধান দিয়ে ফেলেছি।
tglas

3

আমি ভিজুয়াল লিক ডিটেক্টরটিতে ফাঁস মেমরির জন্য স্ট্যাক ট্রেস উত্পন্ন কোডটি ব্যবহার করব । যদিও এটি কেবল উইন 32 এ কাজ করে।


এবং আপনার কোড সহ ডিবাগ প্রতীকগুলি প্রেরণ করা দরকার। সাধারণভাবে কাম্য নয়। একটি মিনি ডাম্প লিখুন এবং উইন্ডোজ সেট আপ না করে ব্যাতিক্রমে আপনার জন্য এটি স্বয়ংক্রিয়ভাবে করুন।
IInspectable

3

আমি এখানে প্রচুর উত্তরগুলি সিগন্যাল হ্যান্ডলার সম্পাদন করে এবং তারপরে প্রস্থান করতে দেখেছি। এটি যাওয়ার উপায়, তবে একটি খুব গুরুত্বপূর্ণ সত্য মনে রাখবেন: উত্পন্ন ত্রুটির জন্য যদি আপনি মূল ডাম্প পেতে চান তবে আপনি কল করতে পারবেন না exit(status)abort()পরিবর্তে কল !


3

উইন্ডোজ-কেবল সমাধান হিসাবে, আপনি উইন্ডোজ ত্রুটি প্রতিবেদন ব্যবহার করে স্ট্যাক ট্রেসের সমতুল্য (অনেক বেশি তথ্য সহ) পেতে পারেন । মাত্র কয়েকটি রেজিস্ট্রি এন্ট্রি সহ এটি ব্যবহারকারী-মোড ডাম্পগুলি সংগ্রহ করতে সেট আপ করা যেতে পারে :

উইন্ডোজ সার্ভার ২০০৮ এবং সার্ভিস প্যাক 1 (এসপি 1) দিয়ে উইন্ডোজ ভিস্তা দিয়ে শুরু করে, উইন্ডোজ ত্রুটি প্রতিবেদন (ডাব্লুইআর) কনফিগার করা যেতে পারে যাতে কোনও ব্যবহারকারী-মোড অ্যাপ্লিকেশন ক্রাশ হওয়ার পরে স্থানীয়ভাবে ব্যবহারকারী-মোড ডাম্পগুলি সংগ্রহ এবং সংরক্ষণ করা যায়। [...]

এই বৈশিষ্ট্যটি ডিফল্টরূপে সক্ষম নয়। বৈশিষ্ট্যটি সক্ষম করার জন্য প্রশাসকের সুযোগ সুবিধাগুলি প্রয়োজন। বৈশিষ্ট্যটি সক্ষম এবং কনফিগার করতে, HKEY_LOCAL_MACHINE OF সফটওয়্যার \ মাইক্রোসফ্ট \ উইন্ডোজ \ উইন্ডোজ ত্রুটি প্রতিবেদনকারী \ লোকালডাম্প কী এর অধীনে নিম্নলিখিত রেজিস্ট্রি মানগুলি ব্যবহার করুন ।

আপনি আপনার ইনস্টলার থেকে রেজিস্ট্রি এন্ট্রি সেট করতে পারেন, এতে প্রয়োজনীয় সুবিধা রয়েছে।

ব্যবহারকারী-মোড ডাম্প তৈরির ক্লায়েন্টটিতে স্ট্যাক ট্রেস তৈরি করার ক্ষেত্রে নিম্নলিখিত সুবিধা রয়েছে:

  • এটি ইতিমধ্যে সিস্টেমে প্রয়োগ করা হয়েছে। আপনি উপরে বর্ণিত হিসাবে WER ব্যবহার করতে পারেন, বা নিজেকে মিনিডাম্প্রাইটডাম্প কল করতে পারেন, যদি আপনার ডাম্প করার পরিমাণের পরিমাণের উপর আরও সূক্ষ্ম নিয়ন্ত্রণের প্রয়োজন হয়। (এটি অন্য কোনও প্রক্রিয়া থেকে কল করতে ভুলবেন না))
  • স্ট্যাক ট্রেসের চেয়ে আরও সম্পূর্ণ উপায় । অন্যদের মধ্যে এটিতে স্থানীয় ভেরিয়েবল, ফাংশন আর্গুমেন্ট, অন্যান্য থ্রেডের স্ট্যাক, লোডযুক্ত মডিউল এবং আরও অনেক কিছু থাকতে পারে। ডেটার পরিমাণ (এবং ফলস্বরূপ আকার) অত্যন্ত স্বনির্ধারিত।
  • ডিবাগ প্রতীক জাহাজের দরকার নেই। এটি উভয়ই আপনার স্থাপনার আকারকে হ্রাস করে তোলে, পাশাপাশি আপনার অ্যাপ্লিকেশনটিকে রিভার্স-ইঞ্জিনিয়ার করা আরও শক্ত করে তোলে।
  • আপনি যে সংকলকটি ব্যবহার করেন তার চেয়ে অনেক বেশি স্বতন্ত্র। WER ব্যবহার করে এমনকি কোনও কোডের প্রয়োজন হয় না। যেভাবেই হোক, একটি প্রতীক ডাটাবেস (পিডিবি) পাওয়ার উপায় থাকা অফলাইন বিশ্লেষণের জন্য খুব দরকারী। আমি বিশ্বাস করি যে জিসিসি হয় হয় পিডিবি তৈরি করতে পারে, বা প্রতীক ডাটাবেসকে পিডিবি ফর্ম্যাটে রূপান্তর করার জন্য এমন সরঞ্জাম রয়েছে।

খেয়াল করুন, কেবলমাত্র একটি অ্যাপ্লিকেশন ক্রাশের মাধ্যমে ডাব্লুইইআরইই ট্রিগার করতে পারে (অর্থাত্‍ ব্যান্ডহীন ব্যতিক্রমের কারণে সিস্টেমটি প্রক্রিয়াটি সমাপ্ত করে)। MiniDumpWriteDumpযে কোনও সময় বলা যেতে পারে। ক্রাশ ব্যতীত অন্যান্য সমস্যাগুলি নির্ণয়ের জন্য আপনার যদি বর্তমান অবস্থা ডাম্প করা প্রয়োজন তবে এটি সহায়ক হতে পারে।

বাধ্যতামূলক পাঠ্য, আপনি যদি মিনি ডাম্পগুলির প্রয়োগযোগ্যতার মূল্যায়ন করতে চান:


2

উপরের উত্তরগুলি ছাড়াও, এখানে আপনি কীভাবে দেবিয়ান লিনাক্স ওএস তৈরি করেন কোর ডাম্প উত্পন্ন করে

  1. ব্যবহারকারীর হোম ফোল্ডারে একটি "করডাম্পস" ফোল্ডার তৈরি করুন
  2. /Etc/security/limits.conf এ যান। '' লাইনের নীচে, মূল ডাম্পগুলির জন্য সীমাহীন স্থানের অনুমতি দেওয়ার জন্য, মূলের ডাম্পগুলিকে সক্ষম করার জন্য "সফট কোর আনলিমিটেড" এবং "রুট সফট কোর আনলিমিটেড" টাইপ করুন।
  3. দ্রষ্টব্য: "* নরম কোর আনলিমিটেড" রুটকে কভার করে না, এই কারণেই রুটটিকে তার নিজস্ব লাইনে নির্দিষ্ট করতে হবে।
  4. এই মানগুলি পরীক্ষা করতে, লগ আউট করুন, আবার লগ ইন করুন এবং "ulimit -a" টাইপ করুন। "কোর ফাইলের আকার" সীমাহীনতে সেট করা উচিত।
  5. Ulimit সেখানে সেট করা নেই তা নিশ্চিত করার জন্য .bashrc ফাইলগুলি (ব্যবহারকারী এবং root প্রযোজ্য ক্ষেত্রে) পরীক্ষা করে দেখুন। অন্যথায়, উপরের মানটি প্রারম্ভকালে ওভাররাইট করা হবে।
  6. /Etc/sysctl.conf খুলুন। নীচে নীচের অংশে প্রবেশ করুন: "কর্নেল.কম_প্যাটার্ন = / হোম অ্যাসোসক্রোডাম্পস / ৯০ ই_৯t.dump"। (% e হবে প্রক্রিয়াটির নাম এবং% টি হবে সিস্টেম সময়)
  7. নতুন কনফিগারেশন চেক / প্রোক / সিএস / কার্নেল / কোর_প্যাটার্ন লোড করতে প্রস্থান করুন এবং টাইপ করুন “সিসেক্টল-পি” এবং যা সুনির্দিষ্টভাবে আপনি টাইপ করেছেন তার সাথে এটি মেলে কিনা তা যাচাই করুন।
  8. কন্ডার ডাম্পিং কমান্ড লাইনে ("&") প্রক্রিয়া চালিয়ে এবং তারপরে "কিল -11" দিয়ে হত্যা করে পরীক্ষা করা যেতে পারে। যদি কোর ডাম্পিং সফল হয় তবে আপনি বিভাগের ত্রুটি ইঙ্গিতের পরে "(কোর ডাম্পড)" দেখতে পাবেন।

2

যদি আপনি এখনও এটি একা যেতে চান তবে আমি এর বিরুদ্ধে লিঙ্ক করতে bfdএবং ব্যবহার এড়াতে পারিaddr2line এখানে :

https://github.com/gnif/LookingGlass/blob/master/common/src/crash.linux.c

এটি আউটপুট উত্পাদন করে:

[E]        crash.linux.c:170  | crit_err_hdlr                  | ==== FATAL CRASH (a12-151-g28b12c85f4+1) ====
[E]        crash.linux.c:171  | crit_err_hdlr                  | signal 11 (Segmentation fault), address is (nil)
[E]        crash.linux.c:194  | crit_err_hdlr                  | [trace]: (0) /home/geoff/Projects/LookingGlass/client/src/main.c:936 (register_key_binds)
[E]        crash.linux.c:194  | crit_err_hdlr                  | [trace]: (1) /home/geoff/Projects/LookingGlass/client/src/main.c:1069 (run)
[E]        crash.linux.c:194  | crit_err_hdlr                  | [trace]: (2) /home/geoff/Projects/LookingGlass/client/src/main.c:1314 (main)
[E]        crash.linux.c:199  | crit_err_hdlr                  | [trace]: (3) /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xeb) [0x7f8aa65f809b]
[E]        crash.linux.c:199  | crit_err_hdlr                  | [trace]: (4) ./looking-glass-client(_start+0x2a) [0x55c70fc4aeca]

1

লিনাক্স / ইউনিক্স / ম্যাকোএসএক্স-এ কোর ফাইলগুলি ব্যবহার করুন (আপনি সেগুলিকে উলিমিট বা সামঞ্জস্যপূর্ণ সিস্টেম কল দিয়ে সক্ষম করতে পারেন )। উইন্ডোজ মাইক্রোসফ্ট ত্রুটি প্রতিবেদন ব্যবহার করুন (আপনি অংশীদার হয়ে উঠতে পারেন এবং আপনার অ্যাপ্লিকেশন ক্র্যাশ ডেটাতে অ্যাক্সেস পেতে পারেন)।


0

আমি "অ্যাপোর্ট" এর জিনোম প্রযুক্তি সম্পর্কে ভুলে গেছি, তবে এটি ব্যবহার সম্পর্কে আমি খুব বেশি জানি না। এটি প্রক্রিয়াজাতকরণের জন্য স্ট্যাকট্রেস এবং অন্যান্য ডায়াগনস্টিকস তৈরি করতে ব্যবহৃত হয় এবং স্বয়ংক্রিয়ভাবে বাগ ফাইল করতে পারে। এটি অবশ্যই চেক ইন মূল্য।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.