Các công cụ để có được biểu đồ lệnh gọi hàm tượng hình của mã [đã đóng]


106

Tôi có một không gian làm việc lớn có nhiều tệp nguồn mã C. Mặc dù tôi có thể thấy các hàm được gọi từ một hàm trong MS VS2005 bằng trình duyệt Đối tượng và trong MSVC 6.0 cũng vậy, điều này chỉ hiển thị các hàm được gọi từ một hàm cụ thể trong kiểu hiển thị không đồ họa. Ngoài ra, nó không hiển thị hàm được gọi là bắt đầu từ say main(), và sau đó là các hàm được gọi từ nó, v.v., sâu hơn bên trong đến hàm mức lá.

Tôi cần một công cụ cung cấp cho tôi biểu đồ lệnh gọi hàm bằng hình ảnh với các hàm calleecallerđược kết nối bằng các mũi tên hoặc thứ gì đó tương tự, bắt đầu từ main()cấp cuối cùng của hàm hoặc ít nhất là hiển thị biểu đồ lệnh gọi của tất cả các hàm trong một tệp nguồn C. Sẽ thật tuyệt nếu tôi có thể in ra biểu đồ này.

Bất kỳ công cụ tốt nào để làm điều đó (không cần phải là công cụ miễn phí)?


Câu trả lời:



29

Phương pháp phân tích động

Ở đây tôi mô tả một vài phương pháp phân tích động.

Các phương thức động thực sự chạy chương trình để xác định đồ thị cuộc gọi.

Đối lập với các phương thức động là các phương thức tĩnh, cố gắng xác định nó từ nguồn một mình mà không cần chạy chương trình.

Ưu điểm của phương pháp động:

  • bắt con trỏ hàm và lệnh gọi C ++ ảo. Chúng hiện diện với số lượng lớn trong bất kỳ phần mềm không tầm thường nào.

Nhược điểm của phương pháp động:

  • bạn phải chạy chương trình, chương trình này có thể chậm hoặc yêu cầu thiết lập mà bạn không có, ví dụ: biên dịch chéo
  • chỉ các hàm thực sự được gọi mới hiển thị. Ví dụ: một số hàm có thể được gọi hoặc không tùy thuộc vào các đối số dòng lệnh.

KcacheGrind

https://kcachegrind.github.io/html/Home.html

Chương trình kiểm tra:

int f2(int i) { return i + 2; }
int f1(int i) { return f2(2) + i + 1; }
int f0(int i) { return f1(1) + f2(2); }
int pointed(int i) { return i; }
int not_called(int i) { return 0; }

int main(int argc, char **argv) {
    int (*f)(int);
    f0(1);
    f1(1);
    f = pointed;
    if (argc == 1)
        f(1);
    if (argc == 2)
        not_called(1);
    return 0;
}

Sử dụng:

sudo apt-get install -y kcachegrind valgrind

# Compile the program as usual, no special flags.
gcc -ggdb3 -O0 -o main -std=c99 main.c

# Generate a callgrind.out.<PID> file.
valgrind --tool=callgrind ./main

# Open a GUI tool to visualize callgrind data.
kcachegrind callgrind.out.1234

Bây giờ bạn đang ở bên trong một chương trình GUI tuyệt vời chứa nhiều dữ liệu hiệu suất thú vị.

Ở dưới cùng bên phải, chọn tab "Biểu đồ cuộc gọi". Điều này hiển thị một biểu đồ cuộc gọi tương tác tương quan với số liệu hiệu suất trong các cửa sổ khác khi bạn nhấp vào các chức năng.

Để xuất biểu đồ, hãy nhấp chuột phải vào biểu đồ đó và chọn "Xuất biểu đồ". PNG được xuất trông giống như sau:

Từ đó chúng ta có thể thấy rằng:

  • nút gốc là _start, là điểm vào ELF thực và chứa bảng soạn khởi tạo glibc
  • f0, f1f2được gọi là như mong đợi từ người khác
  • pointedcũng được hiển thị, mặc dù chúng tôi đã gọi nó bằng một con trỏ hàm. Nó có thể không được gọi nếu chúng ta đã truyền một đối số dòng lệnh.
  • not_called không được hiển thị vì nó không được gọi trong quá trình chạy, vì chúng tôi không chuyển đối số dòng lệnh bổ sung.

Điều thú vị valgrindlà nó không yêu cầu bất kỳ tùy chọn biên dịch đặc biệt nào.

Do đó, bạn có thể sử dụng nó ngay cả khi bạn không có mã nguồn, chỉ có tệp thực thi.

valgrindquản lý để làm điều đó bằng cách chạy mã của bạn thông qua một "máy ảo" nhẹ. Điều này cũng làm cho việc thực thi cực kỳ chậm so với thực thi gốc.

Như có thể thấy trên biểu đồ, thông tin thời gian về mỗi lệnh gọi hàm cũng được thu thập và thông tin này có thể được sử dụng để lập cấu hình chương trình, đây có thể là trường hợp sử dụng ban đầu của thiết lập này, không chỉ để xem biểu đồ cuộc gọi: Làm cách nào để tôi lập cấu hình Mã C ++ chạy trên Linux?

Đã thử nghiệm trên Ubuntu 18.04.

gcc -finstrument-functions + vân vân

https://github.com/elcritch/etrace

-finstrument-functions thêm các lệnh gọi lại , etrace phân tích cú pháp tệp ELF và triển khai tất cả các lệnh gọi lại.

Tuy nhiên, thật không may, tôi không thể làm cho nó hoạt động: Tại sao `-f kinh nguyệt-chức năng` không hoạt động cho tôi?

Đầu ra đã xác nhận có định dạng:

\-- main
|   \-- Crumble_make_apple_crumble
|   |   \-- Crumble_buy_stuff
|   |   |   \-- Crumble_buy
|   |   |   \-- Crumble_buy
|   |   |   \-- Crumble_buy
|   |   |   \-- Crumble_buy
|   |   |   \-- Crumble_buy
|   |   \-- Crumble_prepare_apples
|   |   |   \-- Crumble_skin_and_dice
|   |   \-- Crumble_mix
|   |   \-- Crumble_finalize
|   |   |   \-- Crumble_put
|   |   |   \-- Crumble_put
|   |   \-- Crumble_cook
|   |   |   \-- Crumble_put
|   |   |   \-- Crumble_bake

Có thể là phương pháp hiệu quả nhất bên cạnh hỗ trợ theo dõi phần cứng cụ thể, nhưng có nhược điểm là bạn phải biên dịch lại mã.


2
Chỉ cần lưu ý rằng biểu đồ cuộc gọi động chỉ bao gồm một lần chạy chương trình.
smwikipedia

1
@smwikipedia vâng, tôi đã nâng cấp câu trả lời để làm rõ ràng hơn
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功 30/09/18

Cũng được giải thích ở đây - stackoverflow.com/questions/311840/…
tauseef_CuriousGuy

17

Hiểu thực hiện rất tốt công việc tạo đồ thị cuộc gọi.


9

Bộ công cụ cải tiến phần mềm DMS của chúng tôi có phân tích đồ thị điều khiển tĩnh / luồng dữ liệu / điểm đến / cuộc gọi đã được áp dụng cho các hệ thống khổng lồ (~~ 25 triệu dòng) mã C và tạo ra các đồ thị cuộc gọi như vậy, bao gồm các hàm được gọi thông qua con trỏ hàm .


1
Ah, tốt, năm 2016 của nó và bây giờ là một người giảm giá xuất hiện. Tôi chắc chắn rằng phản đối của anh ấy dựa trên một đánh giá chính xác rằng công cụ này không thể làm được điều này. Chà, có lẽ không. Nó chắc chắn làm những gì OP yêu cầu.
Ira Baxter

1
Hãy ủng hộ để chống lại điều đó. Tôi không quan tâm đó là phần mềm hay độc quyền của bạn miễn là nó hoàn thành công việc :-)
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功


5

Bạn có thể xem trình tạo cây cuộc gọi C dựa trên bash của tôi tại đây . Nó cho phép bạn chỉ định một hoặc nhiều hàm C mà bạn muốn thông tin về người gọi và / hoặc được gọi hoặc bạn có thể chỉ định một tập hợp các hàm và xác định đồ thị khả năng tiếp cận của các lệnh gọi hàm kết nối chúng ... Tức là hãy cho tôi biết tất cả các cách chính ( ), foo () và bar () được kết nối với nhau. Nó sử dụng graphviz / dot cho một công cụ vẽ đồ thị.


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.