เครื่องมือในการรับกราฟการเรียกฟังก์ชันภาพของรหัส [ปิด]


107

ฉันมีพื้นที่ทำงานขนาดใหญ่ซึ่งมีซอร์สไฟล์รหัส C จำนวนมาก แม้ว่าฉันจะเห็นฟังก์ชันที่เรียกจากฟังก์ชันใน MS VS2005 โดยใช้เบราว์เซอร์ Object และใน MSVC 6.0 ก็แสดงเฉพาะฟังก์ชันที่เรียกจากฟังก์ชันเฉพาะในการแสดงผลที่ไม่ใช่กราฟิก นอกจากนี้ยังไม่แสดงฟังก์ชันที่เรียกว่าเริ่มต้นจากการพูดmain()และจากนั้นฟังก์ชันที่เรียกจากฟังก์ชันดังกล่าวและอื่น ๆ ที่ลึกลงไปในฟังก์ชันระดับใบ

ฉันต้องการเครื่องมือที่จะให้กราฟการเรียกใช้ฟังก์ชันเป็นภาพที่มีฟังก์ชันcalleeและcallerเชื่อมต่อด้วยลูกศรหรืออะไรทำนองนั้นโดยเริ่มจากmain()ฟังก์ชันระดับสุดท้ายหรืออย่างน้อยก็แสดงกราฟการโทรของฟังก์ชันทั้งหมดในไฟล์ต้นฉบับ C ไฟล์เดียว จะดีมากถ้าฉันสามารถพิมพ์กราฟนี้ได้

มีเครื่องมือที่ดีในการทำเช่นนั้น (ไม่จำเป็นต้องเป็นเครื่องมือฟรี)?


4
ที่เกี่ยวข้อง: stackoverflow.com/a/17844310/1959808
Ioannis Filippidis

คำตอบ:


54

2
qusetion เกี่ยวกับ CodeViz ถ้าคุณส่งรหัสของคุณไปมันจะสร้างรหัสหรือไม่หรือคุณควรสร้างกราฟด้วย codevis?
Mohammad Reza Rezwani

5
ฉันเพิ่งลองอียิปต์ มันเป็นภาพที่น่ากลัว ฉันไม่แน่ใจเกี่ยวกับคนอื่น ๆ
ar2015

29

วิธีการวิเคราะห์แบบไดนามิก

ที่นี่ฉันจะอธิบายวิธีการวิเคราะห์แบบไดนามิกบางส่วน

วิธีการแบบไดนามิกเรียกใช้โปรแกรมเพื่อกำหนดกราฟการโทร

วิธีที่ตรงกันข้ามกับวิธีไดนามิกคือวิธีการแบบคงที่ซึ่งพยายามกำหนดจากแหล่งที่มาเพียงอย่างเดียวโดยไม่ต้องเรียกใช้โปรแกรม

ข้อดีของวิธีการแบบไดนามิก:

  • จับตัวชี้ฟังก์ชันและการเรียกใช้ C ++ เสมือน สิ่งเหล่านี้มีอยู่เป็นจำนวนมากในซอฟต์แวร์ที่ไม่สำคัญ

ข้อเสียของวิธีการแบบไดนามิก:

  • คุณต้องรันโปรแกรมซึ่งอาจจะช้าหรือต้องใช้การตั้งค่าที่คุณไม่มีเช่นการคอมไพล์ข้าม
  • เฉพาะฟังก์ชันที่ถูกเรียกใช้จริงเท่านั้นที่จะแสดง เช่นบางฟังก์ชันอาจถูกเรียกหรือไม่ขึ้นอยู่กับอาร์กิวเมนต์บรรทัดคำสั่ง

KcacheGrind

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

โปรแกรมทดสอบ:

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;
}

การใช้งาน:

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

ตอนนี้คุณเหลืออยู่ในโปรแกรม GUI ที่ยอดเยี่ยมซึ่งมีข้อมูลประสิทธิภาพที่น่าสนใจมากมาย

ที่ด้านขวาล่างเลือกแท็บ "กราฟการโทร" แสดงกราฟการโทรแบบโต้ตอบที่สัมพันธ์กับเมตริกประสิทธิภาพในหน้าต่างอื่น ๆ เมื่อคุณคลิกฟังก์ชัน

ในการส่งออกกราฟให้คลิกขวาแล้วเลือก "ส่งออกกราฟ" PNG ที่ส่งออกมีลักษณะดังนี้:

จากนั้นเราจะเห็นว่า:

  • โหนดรูทคือ_startซึ่งเป็นจุดเริ่มต้นของ ELF ที่แท้จริงและมีบอยเลอร์การเริ่มต้นของ glibc
  • f0, f1และf2จะเรียกว่าเป็นที่คาดหวังจากคนอื่น
  • pointedจะแสดงด้วยแม้ว่าเราจะเรียกมันด้วยตัวชี้ฟังก์ชันก็ตาม อาจไม่มีการเรียกใช้หากเราผ่านอาร์กิวเมนต์บรรทัดคำสั่ง
  • not_called ไม่แสดงเนื่องจากไม่ได้รับการเรียกใช้ในการรันเนื่องจากเราไม่ได้ส่งผ่านอาร์กิวเมนต์บรรทัดคำสั่งเพิ่มเติม

สิ่งที่น่าสนใจvalgrindคือไม่ต้องการตัวเลือกการรวบรวมพิเศษใด ๆ

ดังนั้นคุณสามารถใช้งานได้แม้ว่าคุณจะไม่มีซอร์สโค้ด แต่มีเพียงไฟล์ปฏิบัติการเท่านั้น

valgrindจัดการได้โดยการรันโค้ดของคุณผ่าน "เครื่องเสมือน" ที่มีน้ำหนักเบา นอกจากนี้ยังทำให้การดำเนินการช้ามากเมื่อเทียบกับการดำเนินการแบบเนทีฟ

ดังที่เห็นได้จากกราฟข้อมูลเวลาเกี่ยวกับการเรียกใช้ฟังก์ชันแต่ละครั้งและสามารถใช้ในการกำหนดโปรไฟล์โปรแกรมซึ่งน่าจะเป็นกรณีการใช้งานดั้งเดิมของการตั้งค่านี้ไม่ใช่เพื่อดูกราฟการโทร: ฉันจะทำโปรไฟล์ได้อย่างไร โค้ด C ++ ทำงานบน Linux?

ทดสอบบน Ubuntu 18.04

gcc -finstrument-functions + etrace

https://github.com/elcritch/etrace

-finstrument-functions เพิ่มการเรียกกลับ etrace แยกวิเคราะห์ไฟล์ ELF และดำเนินการเรียกกลับทั้งหมด

ฉันไม่สามารถใช้งานได้ แต่น่าเสียดาย: เหตุใด "-finstrument-functions" จึงไม่ทำงานสำหรับฉัน

ผลลัพธ์ที่อ้างสิทธิ์เป็นรูปแบบ:

\-- 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

น่าจะเป็นวิธีที่มีประสิทธิภาพมากที่สุดนอกเหนือจากการรองรับการติดตามฮาร์ดแวร์เฉพาะ แต่มีข้อเสียที่คุณต้องคอมไพล์โค้ดใหม่


2
โปรดทราบว่ากราฟการโทรแบบไดนามิกครอบคลุมการเรียกใช้โปรแกรมเพียงครั้งเดียวเท่านั้น
smwikipedia

1
@smwikipedia ใช่ฉันได้อัปเกรดคำตอบเพื่อให้ชัดเจนขึ้นแล้ว
Ciro Santilli 郝海东冠状病六四事件法轮功

อธิบายไว้ที่นี่ด้วย - stackoverflow.com/questions/311840/…
tauseef_CuriousGuy


9

เราDMS ซอฟแวร์การปรับรื้อ Toolkitมีการควบคุม dataflow วิเคราะห์แบบคงที่ / / จุดต่อ / โทรกราฟที่ได้รับนำไปใช้กับระบบขนาดใหญ่ (~~ 25 ล้านบรรทัด) รหัส C, และผลิตกราฟโทรดังกล่าวรวมถึงฟังก์ชั่นที่เรียกว่าผ่านคำแนะนำการทำงาน


1
อาดีปี 2016 และตอนนี้มีผู้โหวตลดลง ฉันแน่ใจว่าการลงคะแนนของเขามาจากการประเมินที่ถูกต้องซึ่งเครื่องมือนี้ไม่สามารถทำได้ อาจจะไม่ แน่นอนว่าสิ่งที่ OP ร้องขอ
Ira Baxter

1
เพิ่มคะแนนเพื่อตอบโต้สิ่งนั้น ฉันไม่สนใจว่ามันจะเป็นซอฟต์แวร์หรือกรรมสิทธิ์ของคุณตราบใดที่มันทำงานเสร็จ :-)
Ciro Santilli 郝海东冠状病六四事件法轮功


5

คุณสามารถตรวจสอบ C กำเนิดต้นไม้โทรทุบตีตามฉันที่นี่ ช่วยให้คุณระบุฟังก์ชัน C อย่างน้อยหนึ่งฟังก์ชันที่คุณต้องการให้ผู้โทรและ / หรือข้อมูลเรียกหรือคุณสามารถระบุชุดของฟังก์ชันและกำหนดกราฟความสามารถในการเข้าถึงของการเรียกฟังก์ชันที่เชื่อมต่อ ... กล่าวคือบอกวิธีทั้งหมดหลัก ( ), foo () และ bar () เชื่อมต่ออยู่ ใช้ graphviz / dot สำหรับเครื่องมือสร้างกราฟ


โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.