Cara Menghasilkan grafik panggilan untuk kode C ++

87

Saya mencoba membuat grafik panggilan yang dapat digunakan untuk mengetahui semua kemungkinan jalur eksekusi yang mengenai fungsi tertentu (sehingga saya tidak perlu mencari tahu semua jalur secara manual, karena ada banyak jalur yang mengarah ke fungsi ini ). Misalnya:

path 1: A -> B -> C -> D  
path 2: A -> B -> X -> Y -> D  
path 3: A -> G -> M -> N -> O -> P -> S -> D  
...  
path n: ...

Saya telah mencoba Codeviz dan Doxygen, entah bagaimana kedua hasil tidak menunjukkan apa-apa selain tujuan fungsi target, D. Dalam kasus saya, D adalah fungsi anggota kelas yang objeknya akan dibungkus dalam penunjuk cerdas. Klien akan selalu mendapatkan objek penunjuk cerdas melalui pabrik untuk memanggil D.

Adakah yang tahu bagaimana mencapai ini?

shiouming
sumber

Jawaban:

120
static void D() { }
static void Y() { D(); }
static void X() { Y(); }
static void C() { D(); X(); }
static void B() { C(); }
static void S() { D(); }
static void P() { S(); }
static void O() { P(); }
static void N() { O(); }
static void M() { N(); }
static void G() { M(); }
static void A() { B(); G(); }

int main() {
  A();
}

Kemudian

$ clang++ -S -emit-llvm main1.cpp -o - | opt -analyze -dot-callgraph
$ dot -Tpng -ocallgraph.png callgraph.dot

Menghasilkan beberapa gambar mengkilap (ada "node eksternal", karena mainmemiliki hubungan eksternal dan mungkin juga dipanggil dari luar unit terjemahan itu):

Callgraph

Anda mungkin ingin melakukan postprocess ini dengan c++filt, sehingga Anda bisa mendapatkan nama-nama fungsi dan kelas yang terlibat. Seperti berikut ini

#include <vector>

struct A { 
  A(int);
  void f(); // not defined, prevents inlining it!
};

int main() {
  std::vector<A> v;
  v.push_back(42);
  v[0].f();
}

$ clang++ -S -emit-llvm main1.cpp -o - |
   opt -analyze -std-link-opts -dot-callgraph
$ cat callgraph.dot | 
   c++filt | 
   sed 's,>,\\>,g; s,-\\>,->,g; s,<,\\<,g' | 
   gawk '/external node/{id=$1} $1 != id' | 
   dot -Tpng -ocallgraph.png    

Menghasilkan keindahan ini (oh my, ukuran tanpa pengoptimalan yang diaktifkan terlalu besar!)

Kecantikan

Fungsi mistik tanpa nama itu Node0x884c4e0,, adalah placeholder yang diasumsikan dipanggil oleh fungsi apa pun yang definisinya tidak diketahui.

Johannes Schaub - litb
sumber
24
Sudahkah Anda melakukan ini pada proyek multi file? terlihat sangat keren sebagai alat
dirvine
2
+1 Untuk beberapa alasan saya harus memberikan opsi -n ke c ++ filt agar nama-nama tersebut dapat diurai. Saya pikir saya akan menyebutkannya di sini jika ada orang lain yang menghadapi masalah yang sama.
Aky
1
Saya mendapatkan kesalahan saat mencoba ini: Pass::print not implemented for pass: 'Print call graph to 'dot' file'!Ada apa dengan itu? dentang 3.8
Arne
2
Ketemu: Saya harus menghapus -analyzeopsi karena beberapa alasan. T lain: dapatkah saya menyetel nama file keluaran ke selain ./callgraph.dot?
Arne
2
Pertanyaan kedua yang saya miliki, bagaimana menjalankan perintah ini untuk beberapa file di direktori yang berbeda?
Pemula
18

Anda dapat mencapainya dengan menggunakan doxygen (dengan opsi untuk menggunakan titik untuk pembuatan grafik).

masukkan deskripsi gambar di sini

Dengan Johannes Schaub - litb main.cpp, ini menghasilkan ini:

masukkan deskripsi gambar di sini

doxygen / dot mungkin lebih mudah daripada clang / opt untuk menginstal dan menjalankan. Saya tidak berhasil menginstalnya sendiri dan itulah mengapa saya mencoba mencari solusi alternatif!

jpo38
sumber
1
Bisakah Anda menambahkan contoh bagaimana menjalankan doxygen untuk mendapatkan jendela yang Anda sertakan?
nimble_ninja
@nimble_ninja: Bukankah tangkapan layar dari dialog konfigurasi doxywizard sudah cukup?
jpo38
1
Saya tidak tahu bahwa itu dari doxywizard. Terima kasih!
nimble_ninja
1
Metode terbaik yang pernah ada! :)
Leslie N
Tidak benar-benar layak untuk proyek besar, berjalan selama 24 jam, dokumentasi HTML berukuran gigabyte, masih belum selesai .. melewatkan yang satu ini. Saya hanya perlu grafik panggilan untuk beberapa fungsi tertentu (pohon lengkap ke / dari / antara main () <=> SQL_COMMIT ()).
Gizmo
9

Menghitung grafik panggilan C ++ yang akurat secara statis itu sulit, karena Anda memerlukan parser bahasa yang tepat, pencarian nama yang benar, dan penganalisis poin-ke yang bagus yang menghargai semantik bahasa dengan benar. Doxygen tidak memiliki semua ini, saya tidak tahu mengapa orang mengklaim menyukainya untuk C ++; mudah untuk membuat contoh 10 baris C ++ yang salah menganalisis Doxygen).

Anda mungkin lebih baik menjalankan profiler waktu yang mengumpulkan grafik panggilan secara dinamis (ini menjelaskan tentang kami) dan hanya menjalankan banyak kasus. Profiler tersebut akan menunjukkan kepada Anda grafik panggilan sebenarnya yang dilakukan.

EDIT: Saya tiba-tiba teringat Mengerti untuk C ++ , yang mengklaim dapat membuat grafik panggilan. Saya tidak tahu apa yang mereka gunakan untuk parser, atau apakah mereka melakukan analisis rinci dengan benar; Saya tidak memiliki pengalaman khusus dengan produk mereka.

Saya terkesan dengan jawaban Schaub, menggunakan Clang; Saya berharap Clang memiliki semua elemen dengan benar.

Ira Baxter
sumber
Sayangnya, saya tidak mengetahui semua kasus penggunaan yang dapat memicu fungsi itu :(. Sebenarnya, tujuan akhir saya adalah mencari tahu daftar kasus penggunaan yang menggunakan fungsi itu untuk tujuan debugging. Saya bisa mencari tahu penelepon langsung dengan alat pengindeksan kode, tetapi perlu mencari tahu semua jalur eksekusi untuk analisis lebih lanjut.
melanjutkan
Jadi yang Anda inginkan adalah kondisi eksekusi di mana sebuah metode dipanggil? Kemudian Anda memerlukan grafik panggilan yang lengkap dan akurat, serta kemampuan alat untuk berjalan di sepanjang aliran kontrol di berbagai node dalam grafik panggilan, mengumpulkan ekspresi bersyarat, hingga metode yang diinginkan ditemukan. Saya tidak tahu alat siap pakai yang akan melakukan ini (komentar ini 7 tahun kemudian dari pertanyaan); Anda mungkin memerlukan mesin analisis khusus untuk melakukan ini. Dentang mungkin ditekan ke dalam ini; toolkit DMS kami dapat digunakan untuk ini.
Ira Baxter
5

Anda dapat menggunakan CppDepend , ini dapat menghasilkan berbagai jenis grafik

  • Grafik Ketergantungan
  • Grafik Panggilan
  • Grafik Warisan Kelas
  • Grafik Kopling
  • Grafik Jalur
  • Semua Grafik Jalur
  • Grafik Siklus

masukkan deskripsi gambar di sini

Issam
sumber
3

Agar clang++perintah untuk menemukan file header standar seperti mpi.hdua opsi tambahan harus digunakan -### -fsyntax-only, yaitu perintah lengkap harus terlihat seperti:

clang++ -### -fsyntax-only -S -emit-llvm main1.cpp -o - | opt -analyze -dot-callgraph
mabalenk.dll
sumber
1

"C ++ Bsc Analyzer" dapat menampilkan grafik panggilan - dengan membaca file yang dihasilkan oleh utilitas bscmake.

Resonantium
sumber
0

doxygen + graphviz dapat menyelesaikan sebagian besar masalah ketika kami ingin membuat grafik panggilan, selanjutnya diserahkan ke tenaga kerja.

Perayapan
sumber
0

Scitools Understand adalah alat yang luar biasa , lebih baik dari semua yang saya ketahui tentang rekayasa balik , dan menghasilkan grafik berkualitas tinggi .

Tapi perhatikan itu cukup mahal dan bahwa versi uji coba memiliki grafik panggilan kupu - kupu yang terbatas hanya pada satu tingkat panggilan (IMHO saya yakin mereka tidak membantu diri mereka sendiri melakukannya ...)

franckspike.dll
sumber