C ++ कोड के लिए कॉलिंग ग्राफ कैसे बनाएं


87

मैं कॉलिंग ग्राफ उत्पन्न करने की कोशिश कर रहा हूं जिसके साथ किसी विशेष फ़ंक्शन को मारने वाले सभी संभावित निष्पादन पथों का पता लगाना है (ताकि मुझे मैन्युअल रूप से सभी पथों का पता लगाने की ज़रूरत नहीं है, क्योंकि कई फ़ंक्शन हैं जो इस फ़ंक्शन का नेतृत्व करते हैं )। उदाहरण के लिए:

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

मैंने कोडविज़ और डॉक्सीजीन की कोशिश की है, किसी भी तरह दोनों परिणाम लक्ष्य समारोह के कुछ भी नहीं दिखाते हैं, डी। मेरे मामले में, डी एक वर्ग का सदस्य फ़ंक्शन है जिसका ऑब्जेक्ट स्मार्ट पॉइंटर के भीतर लपेटा जाएगा। डी को लागू करने के लिए ग्राहक हमेशा कारखाने के माध्यम से स्मार्ट पॉइंटर ऑब्जेक्ट प्राप्त करेंगे।

क्या किसी को पता है कि यह कैसे प्राप्त करने के लिए?

जवाबों:


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

फिर

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

कुछ चमकदार तस्वीर देता है (एक "बाहरी नोड" है, क्योंकि mainबाहरी संबंध है और उस अनुवाद इकाई के बाहर से भी कॉल किया जा सकता है):

Callgraph

आप इसके साथ पोस्टप्रॉसेस करना चाह सकते हैं c++filt, ताकि आप इसमें शामिल फ़ंक्शंस और क्लासेस के अनमैन्डल नाम प्राप्त कर सकें। जैसे निम्नलिखित में

#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    

इस सुंदरता की पैदावार (ओह मेरी, अनुकूलन के बिना आकार बहुत बड़ा था!)

सुंदरता

वह रहस्यमय अनाम फ़ंक्शन, Node0x884c4e0एक प्लेसहोल्डर है जिसे किसी भी फ़ंक्शन द्वारा बुलाया जाना माना जाता है, जिसकी परिभाषा ज्ञात नहीं है।


22
क्या आपने मल्टी फाइल प्रोजेक्ट पर ऐसा किया है? एक उपकरण के रूप में बहुत अच्छा लग रहा है
dirvine

2
+1 किसी कारण से मुझे नाम को अनमैंगल करने के लिए c ++ filt पास करना था। मैंने सोचा कि अगर किसी और को भी इस मुद्दे का सामना करना पड़े तो मैं इसका उल्लेख करूंगा।
अकी

1
मुझे यह प्रयास करते समय एक त्रुटि मिलती है: इसके साथ Pass::print not implemented for pass: 'Print call graph to 'dot' file'!क्या हो रहा है? क्लैंग 3.8
अर्ने

2
यह मिला: मुझे -analyzeकिसी कारण से विकल्प को हटाना होगा । एक और प्रश्न: मैं उत्पादन फ़ाइल नाम के अलावा कुछ और करने के लिए सेट कर सकते हैं ./callgraph.dot?
Arne

2
दूसरा प्रश्न मेरे पास है, विभिन्न निर्देशिकाओं में कई फाइलों के लिए इस कमांड को कैसे चलाना है?
नौसिखिया

18

आप इसे प्राप्त कर सकते हैं doxygen का उपयोग करके (ग्राफ पीढ़ी के लिए डॉट का उपयोग करने के विकल्प के साथ)।

यहाँ छवि विवरण दर्ज करें

जोहान्स शाउब के साथ - litb main.cpp, यह इसे उत्पन्न करता है:

यहाँ छवि विवरण दर्ज करें

doxygen / dot शायद स्थापित करने और चलाने के लिए क्लैंग / ऑप्ट की तुलना में आसान है। मैंने इसे स्वयं स्थापित करने का प्रबंधन नहीं किया और इसीलिए मैंने एक वैकल्पिक समाधान खोजने की कोशिश की!


1
क्या आप उस विंडो को प्राप्त करने के लिए डॉकटीज़ को चलाने का एक उदाहरण जोड़ सकते हैं जिसे आपने शामिल किया था?
nimble_ninja

@nimble_ninja: doxywizard कॉन्फ़िगरेशन डायलॉग से स्क्रीनशॉट पर्याप्त नहीं है?
jpo38

1
मुझे नहीं पता था कि यह doxywizard का था। धन्यवाद!
nimble_ninja

1
सबसे अच्छा तरीका कभी! :)
लेस्ली एन

वास्तव में एक बड़ी परियोजना के लिए व्यवहार्य नहीं है, 24H के लिए चला गया, HTML प्रलेखन के गीगाबाइट्स, अभी भी नहीं किया गया है .. इस एक को छोड़ देना। मुझे बस कुछ विशिष्ट कार्यों (मुख्य से / के बीच / से पूरा पेड़ के लिए कॉल करने की आवश्यकता है) <=> SQL_COMMIT ())।
Gizmo

9

एक सटीक C ++ कॉल ग्राफ़ को स्टेटिक रूप से गणना करना कठिन है, क्योंकि आपको एक सटीक लैंग्वेज पार्सर, सही नाम लुकअप, और एक अच्छा पॉइंट-टू एनालाइज़र चाहिए जो भाषा के शब्दार्थों को ठीक से सम्मानित करता है। Doxygen का इनमें से कोई भी नहीं है, मुझे नहीं पता कि लोग C ++ के लिए इसे पसंद करने का दावा क्यों करते हैं; यह एक 10 लाइन C ++ उदाहरण का निर्माण करना आसान है जो Doxygen गलत तरीके से विश्लेषण करता है)।

आप टाइमिंग प्रोफाइल चलाने वाले से बेहतर हो सकते हैं जो गतिशील रूप से एक कॉल ग्राफ एकत्र करता है (यह हमारा वर्णन करता है) और बस बहुत सारे मामलों का अभ्यास करता है। इस तरह के प्रोफाइल आपको एक्सरसाइज किए गए वास्तविक कॉल ग्राफ को दिखाएंगे।

EDIT: मुझे अचानक C ++ के लिए अंडरस्टैंडिंग याद आया , जो कॉल ग्राफ़ बनाने का दावा करता है। मुझे नहीं पता कि वे पार्सर के लिए क्या उपयोग करते हैं, या क्या वे विस्तृत विश्लेषण सही करते हैं; मुझे उनके उत्पाद के साथ कोई विशिष्ट अनुभव नहीं है।

क्लैंग का उपयोग करते हुए, मैं शाउब के उत्तर से प्रभावित हूं; मुझे उम्मीद है कि क्लैंग के पास सभी तत्व सही होंगे।


दुर्भाग्य से मुझे उन सभी उपयोग मामलों की जानकारी नहीं है जो उस फ़ंक्शन को ट्रिगर कर सकते हैं :( वास्तव में, मेरा अंतिम लक्ष्य उन उपयोग मामलों की सटीक सूची का पता लगाना है जो डिबगिंग उद्देश्य के लिए उस फ़ंक्शन का उपयोग कर रहे हैं। मैं यह पता लगाने में सक्षम हूं। कोड अनुक्रमण उपकरण के साथ प्रत्यक्ष कॉलर्स, लेकिन आगे के विश्लेषण के लिए सभी निष्पादन पथों का पता लगाने की आवश्यकता है।
शिउमिंग

तो क्या आप वास्तव में चाहते हैं कि निष्पादन की स्थिति जिसके तहत एक विधि कहा जाता है? तब आपको एक पूर्ण, सटीक कॉल ग्राफ़ की आवश्यकता होती है, और जब तक वांछित विधि का सामना नहीं किया जाता है, तब तक सशर्त अभिव्यक्तियों को इकट्ठा करते हुए, कॉल ग्राफ़ में विभिन्न नोड्स में नियंत्रण प्रवाह के साथ चलने के लिए एक उपकरण की संक्षिप्तता की आवश्यकता होती है। मुझे किसी भी ऑफ-द-शेल्फ उपकरण का पता नहीं है जो ऐसा करेगा (प्रश्न के 7 साल बाद यह टिप्पणी); आपको यह करने के लिए एक कस्टम विश्लेषण इंजन की आवश्यकता होगी। इसमें क्लैंग को दबाया जा सकता है; इसके लिए हमारे डीएमएस टूलकिट का इस्तेमाल किया जा सकता है।
इरा बैक्सटर

5

आप CppDepend का उपयोग कर सकते हैं , यह कई प्रकार के ग्राफ़ उत्पन्न कर सकता है

  • निर्भरता ग्राफ
  • ग्राफ को बुलाओ
  • क्लास इनहेरिटेंस ग्राफ
  • युग्मन ग्राफ
  • पाथ ग्राफ
  • सभी पथ ग्राफ
  • साइकिल ग्राफ

यहाँ छवि विवरण दर्ज करें


3

के लिए आदेश में clang++आदेश की तरह मानक हेडर फाइल को खोजने के लिए mpi.hदो अतिरिक्त विकल्प इस्तेमाल किया जाना चाहिए -### -fsyntax-only, यानी पूरा आदेश के रूप में दिखना चाहिए:

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

1

"C ++ Bsc एनालाइज़र" कॉल ग्राफ़ प्रदर्शित कर सकता है - bscmake उपयोगिता द्वारा उत्पन्न फ़ाइल को पढ़कर।


0

जब हम कॉल ग्राफ जनरेट करना चाहते हैं, तो doxygen + graphviz ज्यादातर समस्याओं को हल कर सकता है।


0

स्किटोलस अंडरस्टैंडिंग एक शानदार उपकरण है, जो मैं रिवर्स इंजीनियरिंग के लिए जानता हूं, से बेहतर है , और उच्च गुणवत्ता वाले ग्राफ़ बनाता है

लेकिन ध्यान दें कि यह काफी महंगा है और परीक्षण संस्करण में इसका तितली कॉल ग्राफ केवल एक स्तर के कॉल तक ही सीमित है (IMHO मुझे विश्वास है कि वे ऐसा करने में खुद की मदद नहीं करते हैं ...)

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.