Cách tạo biểu đồ gọi cho mã C ++


87

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ể xảy ra với 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, vì có nhiều đường dẫn đến hàm này ). Ví dụ:

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ả đều không hiển thị gì ngoại trừ hàm đích, 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 có đối tượng sẽ được bao bọc trong một con trỏ thông minh. 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 làm thế nào để đạt được điều này?

Câu trả lời:


118
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

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

Callgraph

Bạn có thể muốn xử lý sau điều này với c++filt, để bạn có thể nhận được tên riêng của các hàm và lớp liên quan. Giống như 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    

Mang lại vẻ đẹp này (ôi chao, kích thước mà không bật tối ưu hóa quá lớn!)

sắc đẹp, vẻ đẹp

Hàm ẩn danh thần bí đó Node0x884c4e0, là một trình giữ chỗ được cho là được gọi bởi bất kỳ hàm nào chưa được xác định định nghĩa.


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

2
+1 Vì lý do nào đó, tôi phải chuyển tùy chọn -n cho c ++ filt để gỡ bỏ các tên. Tôi nghĩ tôi sẽ đề cập đến nó ở đây trong trường hợp bất kỳ ai khác gặp phải vấn đề tương tự.
Aky

1
Tôi gặp lỗi khi thử điều này: Pass::print not implemented for pass: 'Print call graph to 'dot' file'!Có chuyện gì vậy? clang 3.8
Arne

2
Đã tìm thấy: Tôi phải xóa -analyzetùy chọn vì một số lý do. Một câu hỏi khác: Tôi có thể đặt tên tệp đầu ra thành tên khác ./callgraph.dotkhông?
Arne

2
Câu hỏi thứ hai tôi có, làm thế nào để chạy lệnh này cho nhiều tệp trong các thư mục khác nhau?
Thành viên mới

18

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 đồ thị).

nhập mô tả hình ảnh ở đây

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

nhập mô tả hình ảnh ở đây

doxygen / dot có lẽ dễ cài đặt và chạy hơn clang / opt. Tôi đã không tự cài đặt được 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 để lấy cửa sổ mà bạn đã đưa vào không?
nimble_ninja

@nimble_ninja: Ảnh chụp màn hình từ hộp thoại cấu hình doxywizard chưa đủ sao?
jpo38 Ngày

1
Tôi không biết rằng nó đến từ doxywizard. Cảm ơn!
nimble_ninja

1
Phương pháp tốt nhất từ ​​trước đến nay! :)
Leslie N

Không thực sự khả thi cho một dự án lớn, chạy trong 24H, hàng gigabyte tài liệu HTML, vẫn chưa xong .. bỏ qua cái này. Tôi chỉ cần đồ thị cuộc gọi cho một số hàm cụ thể (cây hoàn chỉnh đến / từ / giữa main () <=> SQL_COMMIT ()).
Gizmo

9

Việc tính toán tĩnh một biểu đồ cuộc gọi C ++ chính xác là rất khó, vì bạn cần một trình phân tích cú pháp ngôn ngữ chính xác, tra cứu tên chính xác và một trình phân tích điểm-tới tốt giúp tôn trọng ngữ nghĩa của ngôn ngữ một cách chính xác. 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 tuyên bố thích nó cho C ++; dễ dàng xây dựng một ví dụ C ++ 10 dòng mà Doxygen phân tích sai).

Bạn có thể tốt hơn nên chạy một trình định thời gian thu thập động một biểu đồ cuộc gọi (điều này mô tả của chúng tôi) và chỉ cần thực hiện nhiều trường hợp. Những người lập hồ sơ như vậy sẽ hiển thị cho bạn biểu đồ cuộc gọi thực tế đã thực hiện.

CHỈNH SỬA: Tôi chợt nhớ ra phần Hiểu cho C ++ , công cụ này tuyên bố xây dựng đồ thị cuộc gọi. Tôi không biết họ sử dụng gì cho trình phân tích cú pháp, hoặc liệu họ có thực hiện đúng 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 bị ấn tượng bởi câu trả lời của Schaub, sử dụng Clang; Tôi mong đợi Clang có tất cả các yếu tố đúng.


Rất tiếc, 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 đó :(. Trên 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 trường hợp sử dụng sử dụng chức năng đó cho mục đích gỡ lỗi. Tôi có thể tìm hiểu người gọi trực tiếp với công cụ mã lập chỉ mục, 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

Vì vậy, những gì bạn thực sự muốn là điều kiện thực thi theo đó một phương thức được gọi là gì? Sau đó, bạn cần một đồ thị cuộc gọi đầy đủ, chính xác và sự hỗ trợ của một công cụ để đi dọc theo luồng điều khiển trong các nút khác nhau trong biểu đồ cuộc gọi, thu thập các biểu thức điều kiện, cho đến khi gặp phương thức mong muốn. Tôi không biết bất kỳ công cụ có sẵn nào sẽ làm điều này (nhận xét này sau 7 năm so với câu hỏi); bạn có thể sẽ cần một công cụ phân tích tùy chỉnh để làm điều này. Clang có thể bị ép vào điều này; bộ công cụ DMS của chúng tôi có thể được sử dụng cho việc này.
Ira Baxter

5

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

  • Biểu đồ phụ thuộc
  • Biểu đồ cuộc gọi
  • Đồ thị kế thừa lớp
  • Đồ thị khớp nối
  • Đồ thị đường dẫn
  • Đồ thị tất cả đường dẫn
  • Đồ thị chu kỳ

nhập mô tả hình ảnh ở đây


3

Để clang++lệnh tìm các tệp tiêu đề chuẩn, mpi.hbạn nên sử dụng hai tùy chọn bổ sung -### -fsyntax-only, tức là lệnh đầy đủ sẽ trông như sau:

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

1

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


0

doxygen + graphviz có thể giải quyết hầu hết các vấn đề khi chúng tôi muốn tạo biểu đồ cuộc gọi, tiếp theo là giao cho nhân lực.


0

Scitools Hiểu là một công cụ tuyệt vời , tốt hơn tất cả những gì tôi biết để thiết kế ngược và tạo đồ thị chất lượng cao .

Nhưng lưu ý rằng nó khá đắt và phiên bản dùng thử có biểu đồ cuộc gọi bướm của nó chỉ giới hạn ở một cấp độ cuộc gọi (IMHO Tôi tin rằng họ không tự giúp mình làm như vậy…)

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.