Backtrace () / backtrace_symbols () işlev adlarını nasıl yazdırabilirim?


91

Linux'a özgüdür backtrace()ve backtrace_symbols()programın bir arama izini oluşturmanıza izin verir. Ancak, programımın adlarını değil, yalnızca işlev adreslerini yazdırır. İşlev adlarını da yazdırmalarını nasıl sağlayabilirim? Ben ile program derleme denedim -gyanı sıra -ggdb. Aşağıdaki test durumu yalnızca şunu yazdırır:

    GERİ TAKİP ------------
    ./a.out () [0x8048616]
    ./a.out () [0x8048623]
    /lib/libc.so.6(__libc_start_main+0xf3) [0x4a937413]
    ./a.out () [0x8048421]
    ----------------------
    

İlk 2 öğenin işlev adlarını da göstermesini istiyorum foovemain

Kod:



btw, function backtrace_symbols_fdile aynı işlemi gerçekleştirir backtrace_symbols(), ancak ortaya çıkan dizeler hemen dosya tanımlayıcısına yazılır fd.
nhnghia

Yanıtlar:


65

Semboller dinamik sembol tablosundan alınır; İhtiyacınız -rdynamicseçeneği gccde sağlar bağlayıcı bir bayrak geçmek yapar, bütün semboller tabloda yerleştirilir.

( GCC kılavuzunun Bağlantı Seçenekleri sayfasına ve / veya glibc kılavuzunun Backtraces sayfasına bakın .)


10
Yine de bu statik semboller için çalışmaz. libunwind@Nemo'nun bahsettiği, statik işlevler için çalışır.
Nathan Kidd

Bir CMake projesinde bu yanlışlıkla olarak ayarlanmıştı ADD_COMPILE_OPTIONS(-rdynamic). Bunun yerine, ADD_LINK_OPTIONS(-rdynamic)istenen davranışa sahip olması veya eşdeğer olması gerekir.
Stéphane

30

Yürütülebilir adresleri kaynak kod dosya adı + satır numarasıyla eşlemek için addr2line komutunu kullanın . -fİşlev adlarını alma seçeneği de verin .

Alternatif olarak libunwind'i deneyin .


3
addr2 satırı, çıktıda dosya adı ve satır numarası içerdiği için güzeldir, ancak yükleyici tarafından yeniden konumlandırmalar yapılır yapılmaz başarısız olur.
Erwan Legrand

... ve ASLR yer değiştirmeleriyle her zamankinden daha yaygın.
Erwan Legrand

@ErwanLegrand: ASLR'den önce, yeniden konumlandırmaların tahmin edilebilir olduğunu ve addr2linepaylaşılan nesnelerdeki adresler için bile güvenilir bir şekilde çalıştığını düşünmüştüm (?) .
Nemo

ASLR'den önce ne kadar iyi çalıştığından emin olamıyorum. Günümüzde, yalnızca "normal" yürütülebilir dosyalar içindeki kodlar için ve DSO'lar ve PIE'ler (Pozisyondan Bağımsız Yürütülebilirler) içindeki kod için başarısız olacaktır. Neyse ki libunwind bunların hepsi için işe yarıyor gibi görünüyor.
Erwan Legrand

Bu tartışmayı unutmuştum. O zamanlar bilmediğim Libbacktrace daha iyi bir seçenek. (Yeni
cevabıma

12

Ian Lance Taylor'ın mükemmel Libbacktrace'i bu sorunu çözüyor. Yığın çözülmesini sağlar ve hem sıradan ELF sembollerini hem de DWARF hata ayıklama sembollerini destekler.

Libbacktrace, çirkin olabilecek tüm sembollerin dışa aktarılmasını gerektirmez ve ASLR bunu bozmaz.

Libbacktrace, başlangıçta GCC dağıtımının bir parçasıydı. Artık Github'da bağımsız bir sürüm bulunabilir:

https://github.com/ianlancetaylor/libbacktrace


2

Eğer ret == -1 ve errno EINTER ise üstteki cevapta bir hata var, tekrar denemelisiniz, ancak ret'i kopyalanmış olarak saymamalısınız (eğer beğenmezseniz, sırf bunun için bir hesap oluşturmayacaksınız)


0

Geri izlemeyi artırın

Her ikisini de yazdırdığı için çok kullanışlı:

  • unmangled C ++ işlev adları
  • Satır numaraları

otomatik olarak sizin için.

Kullanım özeti:

Bunun için minimum çalıştırılabilir bir örnek ve diğer birçok yöntemi şu adreste sağladım: C veya C ++ 'da çağrı yığınını yazdır


Soru [c ++] değil [c] olarak etiketlenmiştir.
Yakov Galka
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.