summaryrefslogtreecommitdiffstats
path: root/meta/packages/oprofile/oprofile/xml_callgraph.patch
blob: 0c2b567614d171e4c3438f5b6330e25552bdee44 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
Index: oprofile/libpp/callgraph_container.cpp
===================================================================
--- oprofile.orig/libpp/callgraph_container.cpp
+++ oprofile/libpp/callgraph_container.cpp
@@ -379,17 +379,19 @@ process(count_array_t total, double thre
 
 		process_children(sym, threshold);
 
-		cg_syms.push_back(sym);
+		cg_syms_objs.push_back(sym);
 	}
+
+	for (unsigned int i = 0; i < cg_syms_objs.size(); i++)
+		cg_syms.push_back(&cg_syms_objs[i]);
 }
 
 
-cg_collection arc_recorder::get_symbols() const
+symbol_collection arc_recorder::get_symbols() const
 {
 	return cg_syms;
 }
 
-
 void callgraph_container::populate(string const & archive_path, 
    list<inverted_profile> const & iprofiles,
    extra_images const & extra, bool debug_info, double threshold,
@@ -580,12 +582,14 @@ column_flags callgraph_container::output
 	column_flags output_hints = cf_none;
 
 	// FIXME: costly: must we access directly recorder map ?
-	cg_collection syms = recorder.get_symbols();
+	symbol_collection syms = recorder.get_symbols();
 
-	cg_collection::const_iterator it;
-	cg_collection::const_iterator const end = syms.end();
-	for (it = syms.begin(); it != end; ++it)
-		output_hints = it->output_hint(output_hints);
+	symbol_collection::iterator it;
+	symbol_collection::iterator const end = syms.end();
+	for (it = syms.begin(); it != end; ++it) {
+		cg_symbol const *cg_symb = dynamic_cast<const cg_symbol *>(*it);
+		output_hints = cg_symb->output_hint(output_hints);
+	}
 
 	return output_hints;
 }
@@ -597,7 +601,7 @@ count_array_t callgraph_container::sampl
 }
 
 
-cg_collection callgraph_container::get_symbols() const
+symbol_collection callgraph_container::get_symbols() const
 {
 	return recorder.get_symbols();
 }
Index: oprofile/libpp/callgraph_container.h
===================================================================
--- oprofile.orig/libpp/callgraph_container.h
+++ oprofile/libpp/callgraph_container.h
@@ -53,7 +53,7 @@ public:
 	         count_array_t const & arc_count);
 
 	/// return all the cg symbols
-	cg_collection get_symbols() const;
+	symbol_collection get_symbols() const;
 
 	/**
 	 * After population, build the final output, and do
@@ -91,7 +91,8 @@ private:
 	map_t sym_map;
 
 	/// final output data
-	cg_collection cg_syms;
+	symbol_collection cg_syms;
+	cg_collection_objs cg_syms_objs;
 };
 
 
@@ -126,7 +127,7 @@ public:
 	count_array_t samples_count() const;
 
 	// return all the cg symbols
-	cg_collection get_symbols() const;
+	symbol_collection get_symbols() const;
 
 private:
 	/**
Index: oprofile/libpp/format_output.cpp
===================================================================
--- oprofile.orig/libpp/format_output.cpp
+++ oprofile/libpp/format_output.cpp
@@ -489,7 +489,7 @@ cg_formatter::cg_formatter(callgraph_con
 }
 
 
-void cg_formatter::output(ostream & out, cg_collection const & syms)
+void cg_formatter::output(ostream & out, symbol_collection const & syms)
 {
 	// amount of spacing prefixing child and parent lines
 	string const child_parent_prefix("  ");
@@ -498,37 +498,37 @@ void cg_formatter::output(ostream & out,
 
 	out << string(79, '-') << endl;
 
-	cg_collection::const_iterator it;
-	cg_collection::const_iterator end = syms.end();
+	symbol_collection::const_iterator it;
+	symbol_collection::const_iterator end = syms.end();
 
 	for (it = syms.begin(); it < end; ++it) {
-		cg_symbol const & sym = *it;
+		cg_symbol const *sym = dynamic_cast<const cg_symbol *>(*it);
 
 		cg_symbol::children::const_iterator cit;
-		cg_symbol::children::const_iterator cend = sym.callers.end();
+		cg_symbol::children::const_iterator cend = sym->callers.end();
 
 		counts_t c;
 		if (global_percent)
 			c.total = counts.total;
 		else
-			c.total = sym.total_caller_count;
+			c.total = sym->total_caller_count;
 
-		for (cit = sym.callers.begin(); cit != cend; ++cit) {
+		for (cit = sym->callers.begin(); cit != cend; ++cit) {
 			out << child_parent_prefix;
 			do_output(out, *cit, cit->sample, c);
 		}
 
-		do_output(out, sym, sym.sample, counts);
+		do_output(out, *sym, sym->sample, counts);
 
 		c = counts_t();
 		if (global_percent)
 			c.total = counts.total;
 		else
-			c.total = sym.total_callee_count;
+			c.total = sym->total_callee_count;
 
-		cend = sym.callees.end();
+		cend = sym->callees.end();
 
-		for (cit = sym.callees.begin(); cit != cend; ++cit) {
+		for (cit = sym->callees.begin(); cit != cend; ++cit) {
 			out << child_parent_prefix;
 			do_output(out, *cit, cit->sample, c);
 		}
@@ -562,6 +562,20 @@ ostringstream bytes_out;
 map<string, size_t> symbol_data_table;
 size_t symbol_data_index = 0;
 
+/* Return any existing index or add to the table */
+size_t xml_get_symbol_index(string const name)
+{
+	size_t index = symbol_data_index;
+	map<string, size_t>::iterator it = symbol_data_table.find(name);
+
+	if (it == symbol_data_table.end()) {
+		symbol_data_table[name] = symbol_data_index++;
+		return index;
+	}
+
+	return it->second;
+}
+
 
 class symbol_details_t {
 public:
@@ -577,14 +591,15 @@ symbol_details_array_t symbol_details;
 size_t detail_table_index = 0;
 
 xml_formatter::
-xml_formatter(profile_container const & p,
+xml_formatter(profile_container const *p,
 		symbol_collection & s)
 	:
 	profile(p),
 	symbols(s),
 	need_details(false)
 {
-	counts.total = profile.samples_count();
+	if (profile)
+		counts.total = profile->samples_count();
 }
 
 
@@ -640,12 +655,11 @@ void xml_formatter::output_symbol_data(o
 		string const image = get_image_name(symb->image_name, true);
 		string const qname = image + ":" + name;
 		map<string, size_t>::iterator sd_it = symbol_data_table.find(qname);
-		size_t si = xml_support->get_symbol_index(it);
 
-		if (sd_it->second == si) {
+		if (sd_it != symbol_data_table.end()) {
 			// first time we've seen this symbol
 			out << open_element(SYMBOL_DATA, true);
-			out << init_attr(TABLE_ID, si);
+			out << init_attr(TABLE_ID, sd_it->second);
 
 			field_datum datum(*symb, symb->sample, 0, counts);
 
@@ -660,9 +674,12 @@ void xml_formatter::output_symbol_data(o
 				output_attribute(out, datum, ff_vma, STARTING_ADDR);
 
 				if (need_details)
-					xml_support->output_symbol_bytes(bytes_out, symb, si);
+					xml_support->output_symbol_bytes(bytes_out, symb, sd_it->second);
 			}
 			out << close_element();
+
+			// seen so remove (otherwise get several "no symbols")
+			symbol_data_table.erase(qname);
 		}
 	}
 	out << close_element(SYMBOL_TABLE);
@@ -675,8 +692,8 @@ output_symbol_details(symbol_entry const
 	if (!has_sample_counts(symb->sample.counts, lo, hi))
 		return "";
 
-	sample_container::samples_iterator it = profile.begin(symb);
-	sample_container::samples_iterator end = profile.end(symb);
+	sample_container::samples_iterator it = profile->begin(symb);
+	sample_container::samples_iterator end = profile->end(symb);
 
 	ostringstream str;
 	for (; it != end; ++it) {
@@ -725,10 +742,10 @@ output_symbol_details(symbol_entry const
 
 void xml_formatter::
 output_symbol(ostream & out,
-	symbol_collection::const_iterator const it, size_t lo, size_t hi)
+	symbol_entry const * symb, size_t lo, size_t hi)
 {
-	symbol_entry const * symb = *it;
 	ostringstream str;
+	size_t indx;
 
 	// output symbol's summary data for each profile class
 	bool got_samples = false;
@@ -750,27 +767,21 @@ output_symbol(ostream & out,
 	
 	string const image = get_image_name(symb->image_name, true);
 	string const qname = image + ":" + name;
-	map<string, size_t>::iterator sd_it = symbol_data_table.find(qname);
-	size_t si = xml_support->get_symbol_index(it);
 
-	// if this is the first time we've seen this symbol, save it's index
-	if (sd_it == symbol_data_table.end())
-		symbol_data_table[qname] = si;
-	else
-		si = sd_it->second;
+	indx = xml_get_symbol_index(qname);
 
-	out << init_attr(ID_REF, si);
+	out << init_attr(ID_REF, indx);
 
 	if (need_details) {
 		ostringstream details;
-		symbol_details_t & sd = symbol_details[si];
+		symbol_details_t & sd = symbol_details[indx];
 		size_t const detail_lo = sd.index;
 
 		string detail_str = output_symbol_details(symb, sd.index, lo, hi);
 
 		if (detail_str.size() > 0) {
 			if (sd.id < 0)
-				sd.id = si;
+				sd.id = indx;
 			details << detail_str;
 		}
 
@@ -826,5 +837,170 @@ output_attribute(ostream & out, field_da
 	}
 }
 
+xml_cg_formatter::
+xml_cg_formatter(callgraph_container const * cg, symbol_collection & s)
+	:
+	xml_formatter(NULL, s),
+	callgraph(cg)
+{
+	counts.total = callgraph->samples_count();
+}
+
+void xml_cg_formatter::output(ostream & out)
+{
+	xml_support->build_subclasses(out);
+
+	xml_support->output_program_structure(out);
+	output_symbol_data(out);
+
+	out << close_element(PROFILE);
+}
+
+void xml_cg_formatter::
+output_symbol_core(ostream & out,
+	symbol_entry const * symb, size_t lo, size_t hi)
+{
+	cg_symbol const * cg_symb = dynamic_cast<const cg_symbol *>(symb);
+	ostringstream str;
+
+	// output symbol's summary data for each profile class
+	bool got_samples = false;
+
+	for (size_t p = lo; p <= hi; ++p) {
+		got_samples |= xml_support->output_summary_data(str,
+		    symb->sample.counts, p);
+	}
+
+	if (!got_samples)
+		return;
+
+	cverb << vxml << " <!-- symbol_ref=" << symbol_names.name(symb->name) << " -->" << endl;
+
+	out << open_element(SYMBOL, true);
+
+	string const name = symbol_names.name(symb->name);
+	assert(name.size() > 0);
+	
+	string const image = get_image_name(symb->image_name, true);
+	string const qname = image + ":" + name;
+
+	string const selfname = symbol_names.demangle(symb->name) + " [self]";
+
+	out << init_attr(ID_REF, xml_get_symbol_index(qname));
+
+	out << close_element(NONE, true);
+
+	out << open_element(CALLERS);
+	if (cg_symb) {
+		cg_symbol::children::const_iterator cit;
+		cg_symbol::children::const_iterator cend = cg_symb->callers.end();
+
+		for (cit = cg_symb->callers.begin(); cit != cend; ++cit) {
+			ostringstream str1;
+			string binary = get_image_name((cit)->app_name, true);
+			string module = get_image_name((cit)->image_name, true);
+
+
+			got_samples = false;
+
+			for (size_t p = lo; p <= hi; ++p) {
+				got_samples |= xml_support->output_summary_data(str1, cit->sample.counts, p);
+			}
+
+			if (!got_samples)
+				continue;
+
+			out << open_element(MODULE, true);
+			out << init_attr(NAME, module) << close_element(NONE, true);
+
+			cverb << vxml << " <!-- symbol_ref=" << symbol_names.name(cit->name) << " -->" << endl;
+
+			out << open_element(SYMBOL, true);
+
+			string const name1 = symbol_names.name(cit->name);
+			assert(name1.size() > 0);
+	
+			string const qname1 = module + ":" + name1;
+
+			out << init_attr(ID_REF, xml_get_symbol_index(qname1));
+
+			out << close_element(NONE, true);
+
+			out << str1.str();
+
+			out << close_element(SYMBOL);
+
+			out << close_element(MODULE);
+		}
+	}
+	out << close_element(CALLERS);
+
+	out << open_element(CALLEES);
+	if (cg_symb) {
+		cg_symbol::children::const_iterator cit;
+		cg_symbol::children::const_iterator cend = cg_symb->callees.end();
+
+		for (cit = cg_symb->callees.begin(); cit != cend; ++cit) {
+			size_t indx;
+			ostringstream str1;
+			string binary = get_image_name((cit)->app_name, true);
+			string module = get_image_name((cit)->image_name, true);
+			bool self = false;
+
+			got_samples = false;
+
+			for (size_t p = lo; p <= hi; ++p) {
+				got_samples |= xml_support->output_summary_data(str1, cit->sample.counts, p);
+			}
+
+			if (!got_samples)
+				continue;
+
+			out << open_element(MODULE, true);
+			out << init_attr(NAME, module) << close_element(NONE, true);
+
+			cverb << vxml << " <!-- symbol_ref=" << symbol_names.name(cit->name) << " -->" << endl;
+
+			out << open_element(SYMBOL, true);
+
+			string name1 = symbol_names.name(cit->name);
+			assert(name1.size() > 0);
+			string const qname1 = module + ":" + name1;
+
+			/* Find any self references and handle */
+		        if (name1 == selfname) {
+				self = true;
+				indx = xml_get_symbol_index(qname);
+			} else
+				indx = xml_get_symbol_index(qname1);
+
+			out << init_attr(ID_REF, indx);
+
+			if (self)
+				out << init_attr(SELFREF, "true");
+
+			out << close_element(NONE, true);
+
+			out << str1.str();
+
+			out << close_element(SYMBOL);
+
+			out << close_element(MODULE);
+		}
+	}
+	out << close_element(CALLEES);
+
+	// output summary
+	out << str.str();
+	out << close_element(SYMBOL);
+}
+
+
+void xml_cg_formatter::
+output_symbol(ostream & out,
+	symbol_entry const * symb, size_t lo, size_t hi)
+{
+	output_symbol_core(out, symb, lo, hi);
+}
 
 } // namespace format_output
Index: oprofile/libpp/format_output.h
===================================================================
--- oprofile.orig/libpp/format_output.h
+++ oprofile/libpp/format_output.h
@@ -201,7 +201,7 @@ public:
 
 	/** output callgraph information according to the previously format
 	 * specifier set by call(s) to add_format() */
-	void output(std::ostream & out, cg_collection const & syms);
+	void output(std::ostream & out, symbol_collection const & syms);
 };
 
 /// class to output a columned format symbols plus diff values
@@ -227,7 +227,7 @@ private:
 class xml_formatter : public formatter {
 public:
 	/// build a ready to use formatter
-	xml_formatter(profile_container const & profile,
+	xml_formatter(profile_container const * profile,
 		symbol_collection & symbols);
 
 	// output body of XML output
@@ -235,9 +235,8 @@ public:
 
 	/** output one symbol symb to out according to the output format
 	 * specifier previously set by call(s) to add_format() */
-	void output_symbol(std::ostream & out,
-		symbol_collection::const_iterator const it,
-		size_t lo, size_t hi);
+	virtual void output_symbol(std::ostream & out,
+		symbol_entry const * symb, size_t lo, size_t hi);
 
 	/// output details for the symbol
 	std::string output_symbol_details(symbol_entry const * symb,
@@ -246,9 +245,12 @@ public:
 	/// set the output_details boolean
 	void show_details(bool);
 
+	// output SymbolData XML elements
+	void output_symbol_data(std::ostream & out);
+
 private:
 	/// container we work from
-	profile_container const & profile;
+	profile_container const * profile;
  
 	// ordered collection of symbols associated with this profile
 	symbol_collection & symbols;
@@ -256,9 +258,6 @@ private:
 	/// true if we need to show details for each symbols
 	bool need_details;
 
-	// output SymbolData XML elements
-	void output_symbol_data(std::ostream & out);
-
 	// count of DetailData items output so far
 	size_t detail_count;
 
@@ -270,6 +269,28 @@ private:
 			      format_flags fl, tag_t tag);
 };
 
+// callgraph XML output version
+class xml_cg_formatter : public xml_formatter {
+public:
+	/// build a ready to use formatter
+	xml_cg_formatter(callgraph_container const * callgraph,
+		symbol_collection & symbols);
+
+	// output body of XML output
+	void output(std::ostream & out);
+
+	/** output one symbol symb to out according to the output format
+	 * specifier previously set by call(s) to add_format() */
+	virtual void output_symbol(std::ostream & out,
+		symbol_entry const * symb, size_t lo, size_t hi);
+
+private:
+	/// container we work from
+	callgraph_container const * callgraph;
+
+	void output_symbol_core(std::ostream & out,
+		symbol_entry const * symb, size_t lo, size_t hi);
+};
 
 } // namespace format_output 
 
Index: oprofile/libpp/symbol.h
===================================================================
--- oprofile.orig/libpp/symbol.h
+++ oprofile/libpp/symbol.h
@@ -55,8 +55,11 @@ struct sample_entry {
 
 
 /// associate a symbol with a file location, samples count and vma address
-struct symbol_entry {
+class symbol_entry {
+public:
 	symbol_entry() : size(0) {}
+	virtual ~symbol_entry() {}
+
 	/// which image this symbol belongs to
 	image_name_id image_name;
 	/// owning application name: identical to image name if profiling
@@ -92,7 +95,8 @@ typedef std::vector<symbol_entry const *
  * the sample counts replaced with the relevant arc counts, whilst
  * the cg_symbol retains its self count.
  */
-struct cg_symbol : public symbol_entry {
+class cg_symbol : public symbol_entry {
+public:
 	cg_symbol(symbol_entry const & sym) : symbol_entry(sym) {}
 
 	typedef std::vector<symbol_entry> children;
@@ -108,9 +112,12 @@ struct cg_symbol : public symbol_entry {
 	count_array_t total_callee_count;
 };
 
+/// a collection of sorted callgraph symbols (the objects themselves)
+typedef std::vector<cg_symbol> cg_collection_objs;
+
 
-/// a collection of sorted callgraph symbols
-typedef std::vector<cg_symbol> cg_collection;
+/// a collection of sorted callgraph symbols (pointers too, compatible with symbol_collection)
+//typedef std::vector<cg_symbol const *> cg_collection;
 
 
 /// for storing diff %ages
Index: oprofile/libpp/symbol_sort.cpp
===================================================================
--- oprofile.orig/libpp/symbol_sort.cpp
+++ oprofile/libpp/symbol_sort.cpp
@@ -146,23 +146,6 @@ sort(symbol_collection & syms, bool reve
 
 
 void sort_options::
-sort(cg_collection & syms, bool reverse_sort, bool lf) const
-{
-	long_filenames = lf;
-
-	vector<sort_order> sort_option(options);
-	for (sort_order cur = first; cur != last; cur = sort_order(cur + 1)) {
-		if (find(sort_option.begin(), sort_option.end(), cur) ==
-		    sort_option.end())
-			sort_option.push_back(cur);
-	}
-
-	stable_sort(syms.begin(), syms.end(),
-	            symbol_compare(sort_option, reverse_sort));
-}
-
-
-void sort_options::
 sort(diff_collection & syms, bool reverse_sort, bool lf) const
 {
 	long_filenames = lf;
Index: oprofile/libpp/symbol_sort.h
===================================================================
--- oprofile.orig/libpp/symbol_sort.h
+++ oprofile/libpp/symbol_sort.h
@@ -44,12 +44,6 @@ struct sort_options {
 	/**
 	 * Sort the given container by the given criteria.
 	 */
-	void sort(cg_collection & syms, bool reverse_sort,
-	          bool long_filenames) const;
-
-	/**
-	 * Sort the given container by the given criteria.
-	 */
 	void sort(diff_collection & syms, bool reverse_sort,
 	          bool long_filenames) const;
 
Index: oprofile/libpp/xml_utils.cpp
===================================================================
--- oprofile.orig/libpp/xml_utils.cpp
+++ oprofile/libpp/xml_utils.cpp
@@ -257,13 +257,6 @@ void xml_utils::output_xml_header(string
 	cout << close_element(SETUP) << endl;
 }
 
-size_t xml_utils::get_symbol_index(sym_iterator const it)
-{
-	return it - symbols_begin;
-}
-
-
-
 class subclass_info_t {
 public:
 	string unitmask;
@@ -589,7 +582,7 @@ void module_info::output_summary(ostream
 void module_info::output_symbols(ostream & out)
 {
 	for (sym_iterator it = begin; it != end; ++it)
-		xml_out->output_symbol(out, it, lo, hi);
+		xml_out->output_symbol(out, *it, lo, hi);
 }
 
 
Index: oprofile/libutil++/xml_output.cpp
===================================================================
--- oprofile.orig/libutil++/xml_output.cpp
+++ oprofile/libutil++/xml_output.cpp
@@ -47,8 +47,11 @@ string const xml_tag_map[] = {
 	"binary",
 	"module",
 		"name",
+	"callers",
+	"callees",
 	"symbol",
 		"idref",
+		"self",
 		"detaillo",
 		"detailhi",
 	"symboltable",
Index: oprofile/libutil++/xml_output.h
===================================================================
--- oprofile.orig/libutil++/xml_output.h
+++ oprofile/libutil++/xml_output.h
@@ -28,7 +28,8 @@ typedef enum {
 	THREAD, THREAD_ID,
 	BINARY,
 	MODULE, NAME,
-	SYMBOL, ID_REF, DETAIL_LO, DETAIL_HI,
+	CALLERS, CALLEES,
+	SYMBOL, ID_REF, SELFREF, DETAIL_LO, DETAIL_HI,
 	SYMBOL_TABLE,
 	SYMBOL_DATA, STARTING_ADDR,
 		SOURCE_FILE, SOURCE_LINE, CODE_LENGTH,
Index: oprofile/pp/opreport.cpp
===================================================================
--- oprofile.orig/pp/opreport.cpp
+++ oprofile/pp/opreport.cpp
@@ -378,7 +378,7 @@ void output_symbols(profile_container co
 	format_output::opreport_formatter * text_out = 0;
 
 	if (options::xml) {
-		xml_out = new format_output::xml_formatter(pc, symbols);
+		xml_out = new format_output::xml_formatter(&pc, symbols);
 		xml_out->show_details(options::details);
 		out = xml_out;
 		// for XML always output long filenames
@@ -445,25 +445,45 @@ void output_cg_symbols(callgraph_contain
 {
 	column_flags output_hints = cg.output_hint();
 
-	cg_collection symbols = cg.get_symbols();
+	symbol_collection symbols = cg.get_symbols();
+
 	options::sort_by.sort(symbols, options::reverse_sort,
 	                      options::long_filenames);
 
-	format_output::cg_formatter out(cg);
+	format_output::formatter * out;
+	format_output::xml_cg_formatter * xml_out = 0;
+	format_output::cg_formatter * text_out = 0;
 
-	out.set_nr_classes(nr_classes);
-	out.show_long_filenames(options::long_filenames);
-	out.show_header(options::show_header);
-	out.vma_format_64bit(output_hints & cf_64bit_vma);
-	out.show_global_percent(options::global_percent);
+	if (options::xml) {
+		xml_out = new format_output::xml_cg_formatter(&cg, symbols);
+		out = xml_out;
+		// for XML always output long filenames
+		out->show_long_filenames(true);
+	} else {
+		text_out = new format_output::cg_formatter(cg);
+		out = text_out;
+		out->show_long_filenames(options::long_filenames);
+	}
+
+	out->set_nr_classes(nr_classes);
+	out->show_header(options::show_header);
+	out->vma_format_64bit(output_hints & cf_64bit_vma);
+	out->show_global_percent(options::global_percent);
 
 	format_flags flags = get_format_flags(output_hints);
 	if (multiple_apps)
 		flags = format_flags(flags | ff_app_name);
 
-	out.add_format(flags);
+	out->add_format(flags);
+
+	if (options::xml) {
+		xml_support = new xml_utils(xml_out, symbols, nr_classes,
+			&options::symbol_filter, options::archive_path);
+		xml_out->output(cout);
+	} else {
+		text_out->output(cout, symbols);
+	}
 
-	out.output(cout, symbols);
 }
 
 
Index: oprofile/pp/opreport_options.cpp
===================================================================
--- oprofile.orig/pp/opreport_options.cpp
+++ oprofile/pp/opreport_options.cpp
@@ -177,11 +177,6 @@ void check_options(bool diff)
 	}
 
 	if (xml) {
-		if (callgraph) {
-			cerr << "--callgraph is incompatible with --xml" << endl;
-			do_exit = true;
-		}
-
 		if (accumulated) {
 			cerr << "--accumulated is incompatible with --xml" << endl;
 			do_exit = true;