2011-03-21 42 views
64

Tôi đang cố gắng tạo biểu đồ gọi để tìm ra tất cả các đường dẫn thực thi có thể nhấn một hàm cụ thể (để tôi không phải tìm ra tất cả các đường dẫn theo cách thủ công, có nhiều đường dẫn dẫn đến hàm này). Ví dụ:Tạo biểu đồ gọi cho mã C++

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: ... 

Tôi đã thử Codeviz và Doxygen, bằng cách nào đó cả hai kết quả cho thấy không có gì nhưng callees chức năng mục tiêu, D. Trong trường hợp của tôi, D là một hàm thành viên của một lớp mà đối tượng sẽ được bao bọc trong một thông minh con trỏ. Khách hàng sẽ luôn nhận được đối tượng con trỏ thông minh thông qua một nhà máy để gọi D.

Có ai biết cách đạt được điều này không?

Trả lời

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

Sau đó

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

sản lượng một số hình ảnh sáng bóng (có một "nút bên ngoài", bởi vì main có mối liên hệ bên ngoài và có thể được gọi từ bên ngoài đơn vị dịch quá):

Callgraph

Bạn có thể muốn xử lý sau bằng c++filt, để bạn có thể nhận được các tên không bị thay đổi thứ các chức năng và lớp học liên quan. Giống như trong những điều sau

#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  

sản lượng vẻ đẹp này (oh my, kích thước mà không cần tối ưu hóa bật là quá lớn!)

Beauty

Đó chức năng vô danh thần bí, Node0x884c4e0, là một giữ chỗ giả định được gọi bởi bất kỳ hàm nào có định nghĩa không được biết.

+17

Bạn đã làm điều này trên một dự án tập tin đa? trông rất mát mẻ như một công cụ – dirvine

+0

Có cách nào để làm điều này để các chức năng không phải là cục bộ cho các tập tin/tập tin giống như tất cả các chức năng std gọi cho nhau không được gọi? – soandos

+2

+1 Vì lý do nào đó tôi phải chuyển tùy chọn -n thành C++ filt cho các tên để bỏ mặc. Nghĩ rằng tôi sẽ đề cập đến nó ở đây trong trường hợp bất cứ ai khác phải đối mặt với cùng một vấn đề. – Aky

3

Tính toán tĩnh biểu đồ cuộc gọi C++ chính xác rất khó, vì bạn cần trình phân tích ngữ pháp chính xác, tra cứu tên chính xác và điểm phân tích phù hợp với ngữ nghĩa ngôn ngữ. Doxygen không có bất kỳ cái nào trong số này, tôi không biết tại sao mọi người lại yêu thích nó cho C++; thật dễ dàng để xây dựng một ví dụ 10 dòng C++ mà Doxygen phân tích sai).

Bạn có thể nên chạy một số timing profiler which collects a call graph dynamically (mô tả này) và chỉ cần thực hiện rất nhiều trường hợp. Profiler như vậy sẽ cho bạn thấy biểu đồ cuộc gọi thực tế được thực hiện.

EDIT: Tôi đột nhiên nhớ Understand for C++, tuyên bố xây dựng biểu đồ cuộc gọi. Tôi không biết những gì họ sử dụng cho một trình phân tích cú pháp, hoặc liệu họ có thực hiện quyền phân tích chi tiết hay không; Tôi không có kinh nghiệm cụ thể với sản phẩm của họ.

Tôi rất ấn tượng với câu trả lời của Schaub, sử dụng Clang; Tôi mong đợi Clang có đủ mọi yếu tố.

+0

Thật không may là tôi không biết tất cả các trường hợp sử dụng có thể kích hoạt chức năng đó: (Thực tế, mục tiêu cuối cùng của tôi là tìm ra danh sách chính xác các ca sử dụng sử dụng chức năng đó cho mục đích gỡ lỗi.Tôi có thể tìm ra những người gọi trực tiếp với công cụ lập chỉ mục mã, nhưng cần phải tìm ra tất cả các đường dẫn thực hiện để phân tích thêm. – shiouming

3

Để cho lệnh clang++ để tìm tập tin tiêu đề chuẩn như mpi.h hai tùy chọn bổ sung nên được sử dụng -### -fsyntax-only, tức là đầy đủ các lệnh nên xem xét như:

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

Các "C++ Bsc Analyzer" có thể hiển thị gọi đồ thị - bằng cách đọc tệp được tạo bởi tiện ích bscmake.

11

Bạn có thể đạt được điều đó bằng cách sử dụng doxygen (với tùy chọn sử dụng dấu chấm để tạo biểu đồ).

enter image description here

Với Johannes Schaub - litb main.cpp, nó tạo này:

enter image description here

doxygen/dot có lẽ dễ dàng hơn kêu vang/opt để cài đặt và chạy. Tôi không tự mình cài đặt nó và đó là lý do tại sao tôi cố gắng tìm một giải pháp thay thế!

+1

Bạn có thể thêm một ví dụ về cách chạy doxygen để có được cửa sổ mà bạn đã bao gồm không? –

+0

@nimble_ninja: Không phải ảnh chụp màn hình từ hộp thoại cấu hình doxywizard chưa đủ? – jpo38

+0

Tôi không biết đó là do doxywizard. Cảm ơn! –

3

Bạn có thể sử dụng CppDepend, nó có thể tạo ra nhiều loại biểu đồ

  • phụ thuộc Graph
  • Gọi Graph
  • Lớp Inheritance Graph
  • nối Graph
  • Đường dẫn Graph
  • Tất cả Paths Biểu đồ
  • Biểu đồ chu kỳ

enter image description here

Các vấn đề liên quan