1 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
2 // -*- mode: C++ -*-
3 //
4 // Copyright (C) 2013-2021 Red Hat, Inc.
5
6 /// @file
7 ///
8 /// This file contains the definitions of the entry points to
9 /// de-serialize an instance of @ref abigail::translation_unit to an
10 /// ABI Instrumentation file in libabigail native XML format. This
11 /// native XML format is named "abixml".
12
13 #include "config.h"
14 #include <assert.h>
15 #include <algorithm>
16 #include <fstream>
17 #include <iomanip>
18 #include <ios>
19 #include <iostream>
20 #include <memory>
21 #include <sstream>
22 #include <stack>
23 #include <unordered_map>
24 #include <vector>
25
26 #include "abg-tools-utils.h"
27
28 #include "abg-internal.h"
29 // <headers defining libabigail's API go under here>
30 ABG_BEGIN_EXPORT_DECLARATIONS
31
32 #include "abg-config.h"
33 #include "abg-corpus.h"
34 #include "abg-hash.h"
35 #include "abg-sptr-utils.h"
36
37 #include "abg-writer.h"
38 #include "abg-libxml-utils.h"
39 #include "abg-fwd.h"
40
41 ABG_END_EXPORT_DECLARATIONS
42 // </headers defining libabigail's API>
43
44 namespace abigail
45 {
46 using std::cerr;
47 using std::shared_ptr;
48 using std::dynamic_pointer_cast;
49 using std::static_pointer_cast;
50 using std::ofstream;
51 using std::ostream;
52 using std::ostringstream;
53 using std::list;
54 using std::vector;
55 using std::stack;
56 using std::unordered_map;
57 using abigail::sptr_utils::noop_deleter;
58
59 /// The namespace for the native XML file format writer.
60 ///
61 /// It contains utilities to serialize ABI artifacts from the @ref ir
62 /// namespace into the native XML format.
63 namespace xml_writer
64 {
65
66 class id_manager
67 {
68 const environment* m_env;
69 mutable unsigned long long m_cur_id;
70
71 unsigned long long
get_new_id() const72 get_new_id() const
73 { return ++m_cur_id; }
74
75 public:
id_manager(const environment * env)76 id_manager(const environment* env)
77 : m_env(env),
78 m_cur_id(0) {}
79
80 const environment*
get_environment() const81 get_environment() const
82 {return m_env;}
83
84 /// Return a unique string representing a numerical id.
85 interned_string
get_id() const86 get_id() const
87 {
88 ostringstream o;
89 o << get_new_id();
90 const environment* env = get_environment();
91 ABG_ASSERT(env);
92 return env->intern(o.str());
93 }
94
95 /// Return a unique string representing a numerical ID, prefixed by
96 /// prefix.
97 ///
98 /// @param prefix the prefix of the returned unique id.
99 interned_string
get_id_with_prefix(const string & prefix) const100 get_id_with_prefix(const string& prefix) const
101 {
102 ostringstream o;
103 o << prefix << get_new_id();
104 const environment* env = get_environment();
105 ABG_ASSERT(env);
106 return env->intern(o.str());
107 }
108 };
109
110 /// A convenience typedef for a map that associates a pointer to type
111 /// to a string.
112 typedef unordered_map<type_base*, interned_string> type_ptr_map;
113
114 // A convenience typedef for a set of type_base*.
115 typedef std::unordered_set<const type_base*> type_ptr_set_type;
116
117 /// A convenience typedef for a set of function type*.
118 typedef std::unordered_set<function_type*> fn_type_ptr_set_type;
119
120 typedef unordered_map<shared_ptr<function_tdecl>,
121 string,
122 function_tdecl::shared_ptr_hash> fn_tmpl_shared_ptr_map;
123
124 typedef unordered_map<shared_ptr<class_tdecl>,
125 string,
126 class_tdecl::shared_ptr_hash> class_tmpl_shared_ptr_map;
127
128 class write_context
129 {
130 const environment* m_env;
131 id_manager m_id_manager;
132 ostream* m_ostream;
133 bool m_annotate;
134 bool m_show_locs;
135 bool m_write_architecture;
136 bool m_write_corpus_path;
137 bool m_write_comp_dir;
138 bool m_write_elf_needed;
139 bool m_write_parameter_names;
140 bool m_short_locs;
141 bool m_write_default_sizes;
142 type_id_style_kind m_type_id_style;
143 mutable type_ptr_map m_type_id_map;
144 mutable unordered_set<uint32_t> m_used_type_id_hashes;
145 mutable type_ptr_set_type m_emitted_type_set;
146 // A map of types that are referenced by emitted pointers,
147 // references or typedefs
148 type_ptr_set_type m_referenced_types_set;
149 fn_type_ptr_set_type m_referenced_fn_types_set;
150 type_ptr_set_type m_referenced_non_canonical_types_set;
151 fn_tmpl_shared_ptr_map m_fn_tmpl_id_map;
152 class_tmpl_shared_ptr_map m_class_tmpl_id_map;
153 string_elf_symbol_sptr_map_type m_fun_symbol_map;
154 string_elf_symbol_sptr_map_type m_var_symbol_map;
155 unordered_set<interned_string, hash_interned_string> m_emitted_decls_set;
156
157 write_context();
158
159 public:
160
161 /// Constructor.
162 ///
163 /// @param env the enviroment we are operating from.
164 ///
165 /// @param os the output stream to write to.
write_context(const environment * env,ostream & os)166 write_context(const environment* env, ostream& os)
167 : m_env(env),
168 m_id_manager(env),
169 m_ostream(&os),
170 m_annotate(false),
171 m_show_locs(true),
172 m_write_architecture(true),
173 m_write_corpus_path(true),
174 m_write_comp_dir(true),
175 m_write_elf_needed(true),
176 m_write_parameter_names(true),
177 m_short_locs(false),
178 m_write_default_sizes(true),
179 m_type_id_style(SEQUENCE_TYPE_ID_STYLE)
180 {}
181
182 /// Getter of the environment we are operating from.
183 ///
184 /// @return the environment we are operating from.
185 const environment*
get_environment() const186 get_environment() const
187 {return m_env;}
188
189 const config&
get_config() const190 get_config() const
191 {
192 ABG_ASSERT(get_environment());
193 return get_environment()->get_config();
194 }
195
196 /// Getter for the current ostream
197 ///
198 /// @return a reference to the current ostream
199 ostream&
get_ostream()200 get_ostream()
201 {return *m_ostream;}
202
203 /// Setter for the current ostream
204 ///
205 /// @param os the new ostream
206 void
set_ostream(ostream & os)207 set_ostream(ostream& os)
208 {m_ostream = &os;}
209
210 /// Getter of the annotation option.
211 ///
212 /// @return true iff ABIXML annotations are turned on
213 bool
get_annotate()214 get_annotate()
215 {return m_annotate;}
216
217 /// Setter of the annotation option.
218 ///
219 /// @param f the new value of the flag.
220 void
set_annotate(bool f)221 set_annotate(bool f)
222 {m_annotate = f;}
223
224 /// Getter of the write-architecture option.
225 ///
226 /// @return true iff architecture information shall be emitted
227 bool
get_write_architecture()228 get_write_architecture()
229 {return m_write_architecture;}
230
231 /// Setter of the write-architecture option
232 ///
233 /// @param f the new value of the flag.
234 void
set_write_architecture(bool f)235 set_write_architecture(bool f)
236 {m_write_architecture = f;}
237
238 /// Getter of the elf-needed option.
239 ///
240 /// @return true iff elf needed information shall be emitted
241 bool
get_write_elf_needed()242 get_write_elf_needed()
243 {return m_write_elf_needed;}
244
245 /// Setter of the elf-needed option.
246 ///
247 /// @param f the new value of the flag.
248 void
set_write_elf_needed(bool f)249 set_write_elf_needed(bool f)
250 {m_write_elf_needed = f;}
251
252 /// Getter of the default-sizes option.
253 ///
254 /// @return true iff default size-in-bits needs to be emitted
255 bool
get_write_default_sizes()256 get_write_default_sizes()
257 {return m_write_default_sizes;}
258
259 /// Setter of the default-sizes option.
260 ///
261 /// @param f the new value of the flag.
262 void
set_write_default_sizes(bool f)263 set_write_default_sizes(bool f)
264 {m_write_default_sizes = f;}
265
266 /// Getter of the write-corpus-path option.
267 ///
268 /// @return true iff corpus-path information shall be emitted
269 bool
get_write_corpus_path()270 get_write_corpus_path()
271 {return m_write_corpus_path;}
272
273 /// Setter of the write-corpus-path option
274 ///
275 /// @param f the new value of the flag.
276 void
set_write_corpus_path(bool f)277 set_write_corpus_path(bool f)
278 {m_write_corpus_path = f;}
279
280 /// Getter of the comp-dir-path option.
281 ///
282 /// @return true iff compilation dir information shall be emitted
283 bool
get_write_comp_dir()284 get_write_comp_dir()
285 {return m_write_comp_dir;}
286
287 /// Setter of the comp-dir-path option
288 ///
289 /// @param f the new value of the flag.
290 void
set_write_comp_dir(bool f)291 set_write_comp_dir(bool f)
292 {m_write_comp_dir = f;}
293
294 /// Getter of the short-locs option.
295 ///
296 /// @return true iff short locations shall be emitted
297 bool
get_short_locs()298 get_short_locs()
299 {return m_short_locs;}
300
301 /// Setter of the short-locs option
302 ///
303 /// @param f the new value of the flag.
304 void
set_short_locs(bool f)305 set_short_locs(bool f)
306 {m_short_locs = f;}
307
308 /// Getter of the parameter-names option.
309 ///
310 /// @return true iff parameter names shall be emitted
311 bool
get_write_parameter_names() const312 get_write_parameter_names() const
313 {return m_write_parameter_names;}
314
315 /// Setter of the parameter-names option
316 ///
317 /// @param f the new value of the flag.
318 void
set_write_parameter_names(bool f)319 set_write_parameter_names(bool f)
320 {m_write_parameter_names = f;}
321
322 /// Getter of the "show-locs" option.
323 ///
324 /// When this option is true then the XML writer emits location
325 /// information for emitted ABI artifacts.
326 ///
327 /// @return the value of the "show-locs" option.
328 bool
get_show_locs() const329 get_show_locs() const
330 {return m_show_locs;}
331
332 /// Setter of the "show-locs" option.
333 ///
334 /// When this option is true then the XML writer emits location
335 /// information for emitted ABI artifacts.
336 ///
337 /// @param f the new value of the "show-locs" option.
338 void
set_show_locs(bool f)339 set_show_locs(bool f)
340 {m_show_locs = f;}
341
342 /// Getter of the "type-id-style" option.
343 ///
344 /// This option controls the kind of type ids used in XML output.
345 ///
346 /// @return the value of the "type-id-style" option.
347 type_id_style_kind
get_type_id_style() const348 get_type_id_style() const
349 {return m_type_id_style;}
350
351 /// Setter of the "type-id-style" option.
352 ///
353 /// This option controls the kind of type ids used in XML output.
354 ///
355 /// @param style the new value of the "type-id-style" option.
356 void
set_type_id_style(type_id_style_kind style)357 set_type_id_style(type_id_style_kind style)
358 {m_type_id_style = style;}
359
360 /// Getter of the @ref id_manager.
361 ///
362 /// @return the @ref id_manager used by the current instance of @ref
363 /// write_context.
364 const id_manager&
get_id_manager() const365 get_id_manager() const
366 {return m_id_manager;}
367
368 id_manager&
get_id_manager()369 get_id_manager()
370 {return m_id_manager;}
371
372 /// @return true iff type has already been assigned an ID.
373 bool
type_has_existing_id(type_base_sptr type) const374 type_has_existing_id(type_base_sptr type) const
375 {return type_has_existing_id(type.get());}
376
377 /// @return true iff type has already been assigned an ID.
378 bool
type_has_existing_id(type_base * type) const379 type_has_existing_id(type_base* type) const
380 {
381 type = get_exemplar_type(type);
382 return m_type_id_map.find(type) != m_type_id_map.end();
383 }
384
385 /// Associate a unique id to a given type. For that, put the type
386 /// in a hash table, hashing the type. So if the type has no id
387 /// associated to it, create a new one and return it. Otherwise,
388 /// return the existing id for that type.
389 interned_string
get_id_for_type(const type_base_sptr & t)390 get_id_for_type(const type_base_sptr& t)
391 {return get_id_for_type(t.get());}
392
393 /// Associate a unique id to a given type. For that, put the type
394 /// in a hash table, hashing the type. So if the type has no id
395 /// associated to it, create a new one and return it. Otherwise,
396 /// return the existing id for that type.
397 interned_string
get_id_for_type(type_base * type) const398 get_id_for_type(type_base* type) const
399 {
400 type_base* c = get_exemplar_type(type);
401
402 type_ptr_map::const_iterator it = m_type_id_map.find(c);
403 if (it != m_type_id_map.end())
404 return it->second;
405
406 switch (m_type_id_style)
407 {
408 case SEQUENCE_TYPE_ID_STYLE:
409 {
410 interned_string id = get_id_manager().get_id_with_prefix("type-id-");
411 return m_type_id_map[c] = id;
412 }
413 case HASH_TYPE_ID_STYLE:
414 {
415 interned_string pretty = c->get_cached_pretty_representation(true);
416 size_t hash = hashing::fnv_hash(pretty);
417 while (!m_used_type_id_hashes.insert(hash).second)
418 ++hash;
419 std::ostringstream os;
420 os << std::hex << std::setfill('0') << std::setw(8) << hash;
421 return m_type_id_map[c] = c->get_environment()->intern(os.str());
422 }
423 }
424 ABG_ASSERT_NOT_REACHED;
425 return interned_string();
426 }
427
428 string
get_id_for_fn_tmpl(const function_tdecl_sptr & f)429 get_id_for_fn_tmpl(const function_tdecl_sptr& f)
430 {
431 fn_tmpl_shared_ptr_map::const_iterator it = m_fn_tmpl_id_map.find(f);
432 if (it == m_fn_tmpl_id_map.end())
433 {
434 string id = get_id_manager().get_id_with_prefix("fn-tmpl-id-");
435 m_fn_tmpl_id_map[f] = id;
436 return id;
437 }
438 return m_fn_tmpl_id_map[f];
439 }
440
441 string
get_id_for_class_tmpl(const class_tdecl_sptr & c)442 get_id_for_class_tmpl(const class_tdecl_sptr& c)
443 {
444 class_tmpl_shared_ptr_map::const_iterator it = m_class_tmpl_id_map.find(c);
445 if (it == m_class_tmpl_id_map.end())
446 {
447 string id = get_id_manager().get_id_with_prefix("class-tmpl-id-");
448 m_class_tmpl_id_map[c] = id;
449 return id;
450 }
451 return m_class_tmpl_id_map[c];
452 }
453
454 void
clear_type_id_map()455 clear_type_id_map()
456 {m_type_id_map.clear();}
457
458
459 /// Getter of the set of types that were referenced by a pointer,
460 /// reference or typedef.
461 ///
462 /// This set contains only types that do have canonical types and
463 /// which are not function types.
464 ///
465 /// @return the set of types that were referenced.
466 const type_ptr_set_type&
get_referenced_types() const467 get_referenced_types() const
468 {return m_referenced_types_set;}
469
470 /// Getter of the set of function types that were referenced by a
471 /// pointer, reference or typedef.
472 ///
473 /// @return the set of function types that were referenced.
474 const fn_type_ptr_set_type&
get_referenced_function_types() const475 get_referenced_function_types() const
476 {return m_referenced_fn_types_set;}
477
478 /// Getter of the set of types which have no canonical types and
479 /// which were referenced by a pointer, reference or typedef.
480 ///
481 /// @return the of referenced type that have no canonical types.
482 const type_ptr_set_type&
get_referenced_non_canonical_types() const483 get_referenced_non_canonical_types() const
484 {return m_referenced_non_canonical_types_set;}
485
486 /// Test if there are non emitted referenced types.
487 ///
488 /// @return true iff there are non emitted referenced types.
489 bool
has_non_emitted_referenced_types() const490 has_non_emitted_referenced_types() const
491 {
492 for (const auto t : get_referenced_types())
493 if (!type_is_emitted(t))
494 return false;
495
496 for (const auto t : get_referenced_function_types())
497 if (!type_is_emitted(t))
498 return false;
499
500 for (const auto t : get_referenced_non_canonical_types())
501 if (!type_is_emitted(t))
502 return false;
503
504 return true;
505 }
506
507 /// Record a given type as being referenced by a pointer, a
508 /// reference or a typedef type that is being emitted to the XML
509 /// output.
510 ///
511 /// @param t a shared pointer to a type
512 void
record_type_as_referenced(const type_base_sptr & type)513 record_type_as_referenced(const type_base_sptr& type)
514 {
515 type_base* t = get_exemplar_type(type.get());
516 // If the type is a function type, record it in a dedicated data
517 // structure.
518 if (function_type* f = is_function_type(t))
519 m_referenced_fn_types_set.insert(f);
520 else if (!t->get_naked_canonical_type())
521 // If the type doesn't have a canonical type, record it in a
522 // dedicated data structure.
523 m_referenced_non_canonical_types_set.insert(t);
524 else
525 m_referenced_types_set.insert(t);
526 }
527
528 /// Test if a given type has been referenced by a pointer, a
529 /// reference or a typedef type that was emitted to the XML output.
530 ///
531 /// @param f a shared pointer to a type
532 ///
533 /// @return true if the type has been referenced, false
534 /// otherwise.
535 bool
type_is_referenced(const type_base_sptr & type)536 type_is_referenced(const type_base_sptr& type)
537 {
538 type_base* t = get_exemplar_type(type.get());
539 if (function_type* f = is_function_type(t))
540 return (m_referenced_fn_types_set.find(f)
541 != m_referenced_fn_types_set.end());
542 else if (!t->get_naked_canonical_type())
543 return (m_referenced_non_canonical_types_set.find(t)
544 != m_referenced_non_canonical_types_set.end());
545 else
546 return m_referenced_types_set.find(t) != m_referenced_types_set.end();
547 }
548
549 /// A comparison functor to compare pointers to @ref type_base.
550 ///
551 /// What is compared is the string representation of the pointed-to
552 /// type.
553 struct type_ptr_cmp
554 {
555 type_ptr_map *map;
type_ptr_cmpabigail::xml_writer::write_context::type_ptr_cmp556 type_ptr_cmp(type_ptr_map *m)
557 : map(m)
558 {}
559
560 /// The comparison operator of the functor.
561 ///
562 /// @param l the first type to consider.
563 ///
564 /// @param r the second type to consider.
565 ///
566 /// @return true if the string representation of type @p l is
567 /// considered to be "less than" the string representation of the
568 /// type @p r.
569 ///
570 /// But when the two string representations are equal (for
571 /// instance, for typedefs that have the same string
572 /// representation), this function compares the type-ids of the
573 /// types. This allows for a stable result.
574 bool
operator ()abigail::xml_writer::write_context::type_ptr_cmp575 operator()(const type_base* l, const type_base* r) const
576 {
577 if (!l && r)
578 return true;
579 if (l && !r)
580 return false;
581 if (!l && !r)
582 return false;
583
584 string r1 = ir::get_pretty_representation(l, true),
585 r2 = ir::get_pretty_representation(r, true);
586
587 if (r1 == r2)
588 {
589 type_ptr_map::const_iterator i =
590 map->find(const_cast<type_base*>(l));
591 if (i != map->end())
592 r1 = i->second;
593 i = map->find(const_cast<type_base*>(r));
594 if (i != map->end())
595 r2 = i->second;
596 }
597
598 return r1 < r2;
599 }
600
601 /// The comparison operator of the functor.
602 ///
603 /// @param l the first type to consider.
604 ///
605 /// @param r the second type to consider.
606 ///
607 /// @return true if the string representation of type @p l is
608 /// considered to be "less than" the string representation of the
609 /// type @p r.
610 ///
611 /// But when the two string representations are equal (for
612 /// instance, for typedefs that have the same string
613 /// representation), this function compares the type-ids of the
614 /// types. This allows for a stable result.
615 bool
operator ()abigail::xml_writer::write_context::type_ptr_cmp616 operator()(const type_base_sptr& l, const type_base_sptr& r) const
617 {return operator()(l.get(), r.get());}
618 }; // end struct type_ptr_cmp
619
620 /// Sort the content of a map of type pointers into a vector.
621 ///
622 /// The pointers are sorted by using their string representation as
623 /// the key to sort, lexicographically.
624 ///
625 /// @param types the map to sort.
626 ///
627 /// @return the resulting sorted vector.
628 std::vector<type_base*>
sort_types(type_ptr_set_type & types)629 sort_types(type_ptr_set_type& types)
630 {
631 std::vector<type_base*> sorted;
632 sorted.reserve(types.size());
633 for (const type_base* t : types)
634 sorted.push_back(const_cast<type_base*>(t));
635 type_ptr_cmp comp(&m_type_id_map);
636 std::sort(sorted.begin(), sorted.end(), comp);
637 return sorted;
638 }
639
640 /// Sort the content of a vector of function types into a vector of
641 /// types.
642 ///
643 /// The pointers are sorted by using their string representation as
644 /// the key to sort, lexicographically.
645 ///
646 /// @param types the vector of function types to sort.
647 ///
648 /// @return the resulting sorted vector.
649 std::vector<type_base_sptr>
sort_types(const vector<function_type_sptr> & types)650 sort_types(const vector<function_type_sptr>& types)
651 {
652 std::vector<type_base_sptr> sorted;
653 sorted.reserve(types.size());
654 for (const auto& t : types)
655 sorted.push_back(t);
656 type_ptr_cmp comp(&m_type_id_map);
657 std::sort(sorted.begin(), sorted.end(), comp);
658 return sorted;
659 }
660
661 /// Flag a type as having been written out to the XML output.
662 ///
663 /// @param t the type to flag.
664 void
record_type_as_emitted(const type_base_sptr & t)665 record_type_as_emitted(const type_base_sptr &t)
666 {record_type_as_emitted(t.get());}
667
668 /// Flag a type as having been written out to the XML output.
669 ///
670 /// @param t the type to flag.
671 void
record_type_as_emitted(const type_base * t)672 record_type_as_emitted(const type_base* t)
673 {
674 type_base* c = get_exemplar_type(t);
675 m_emitted_type_set.insert(c);
676 }
677
678 /// Test if a given type has been written out to the XML output.
679 ///
680 /// @param the type to test for.
681 ///
682 /// @return true if the type has already been emitted, false
683 /// otherwise.
684 bool
type_is_emitted(const type_base * t) const685 type_is_emitted(const type_base* t) const
686 {
687 type_base* c = get_exemplar_type(t);
688 return m_emitted_type_set.find(c) != m_emitted_type_set.end();
689 }
690
691 /// Test if a given type has been written out to the XML output.
692 ///
693 /// @param the type to test for.
694 ///
695 /// @return true if the type has already been emitted, false
696 /// otherwise.
697 bool
type_is_emitted(const type_base_sptr & t) const698 type_is_emitted(const type_base_sptr& t) const
699 {return type_is_emitted(t.get());}
700
701 /// Test if a given decl has been written out to the XML output.
702 ///
703 /// @param the decl to consider.
704 ///
705 /// @return true if the decl has already been emitted, false
706 /// otherwise.
707 bool
decl_is_emitted(const decl_base_sptr & decl) const708 decl_is_emitted(const decl_base_sptr& decl) const
709 {
710 ABG_ASSERT(!is_type(decl));
711 string repr = get_pretty_representation(decl, true);
712 interned_string irepr = decl->get_environment()->intern(repr);
713 return m_emitted_decls_set.find(irepr) != m_emitted_decls_set.end();
714 }
715
716 /// Record a declaration as emitted in the abixml output.
717 ///
718 /// @param decl the decl to consider.
719 void
record_decl_as_emitted(const decl_base_sptr & decl)720 record_decl_as_emitted(const decl_base_sptr& decl)
721 {
722 string repr = get_pretty_representation(decl, true);
723 interned_string irepr = decl->get_environment()->intern(repr);
724 m_emitted_decls_set.insert(irepr);
725 }
726
727 /// Get the set of types that have been emitted.
728 ///
729 /// @return the set of types that have been emitted.
730 const type_ptr_set_type&
get_emitted_types_set() const731 get_emitted_types_set() const
732 {return m_emitted_type_set;}
733
734 /// Clear the map that contains the IDs of the types that has been
735 /// recorded as having been written out to the XML output.
736 void
clear_referenced_types()737 clear_referenced_types()
738 {
739 m_referenced_types_set.clear();
740 m_referenced_non_canonical_types_set.clear();
741 m_referenced_fn_types_set.clear();
742 }
743
744 const string_elf_symbol_sptr_map_type&
get_fun_symbol_map() const745 get_fun_symbol_map() const
746 {return m_fun_symbol_map;}
747
748 string_elf_symbol_sptr_map_type&
get_fun_symbol_map()749 get_fun_symbol_map()
750 {return m_fun_symbol_map;}
751
752 };//end write_context
753
754 static void write_location(const location&, write_context&);
755 static void write_location(const decl_base_sptr&, write_context&);
756 static bool write_visibility(const decl_base_sptr&, ostream&);
757 static bool write_binding(const decl_base_sptr&, ostream&);
758 static bool write_is_artificial(const decl_base_sptr&, ostream&);
759 static bool write_is_non_reachable(const type_base_sptr&, ostream&);
760 static bool write_tracking_non_reachable_types(const corpus_sptr&, ostream&);
761 static void write_array_size_and_alignment(const array_type_def_sptr,
762 ostream&);
763 static void write_size_and_alignment(const type_base_sptr, ostream&,
764 size_t default_size = 0,
765 size_t default_alignment = 0);
766 static void write_access(access_specifier, ostream&);
767 static void write_layout_offset(var_decl_sptr, ostream&);
768 static void write_layout_offset(class_decl::base_spec_sptr, ostream&);
769 static void write_cdtor_const_static(bool, bool, bool, bool, ostream&);
770 static void write_voffset(function_decl_sptr, ostream&);
771 static void write_elf_symbol_type(elf_symbol::type, ostream&);
772 static void write_elf_symbol_binding(elf_symbol::binding, ostream&);
773 static bool write_elf_symbol_aliases(const elf_symbol&, ostream&);
774 static bool write_elf_symbol_reference(const elf_symbol&, ostream&);
775 static bool write_elf_symbol_reference(const elf_symbol_sptr, ostream&);
776 static void write_is_declaration_only(const decl_base_sptr&, ostream&);
777 static void write_is_struct(const class_decl_sptr&, ostream&);
778 static void write_is_anonymous(const decl_base_sptr&, ostream&);
779 static void write_naming_typedef(const decl_base_sptr&, write_context&);
780 static bool write_decl(const decl_base_sptr&, write_context&, unsigned);
781 static void write_decl_in_scope(const decl_base_sptr&,
782 write_context&, unsigned);
783 static bool write_type_decl(const type_decl_sptr&, write_context&, unsigned);
784 static bool write_namespace_decl(const namespace_decl_sptr&,
785 write_context&, unsigned);
786 static bool write_qualified_type_def(const qualified_type_def_sptr&,
787 write_context&, unsigned);
788 static bool write_pointer_type_def(const pointer_type_def_sptr&,
789 write_context&, unsigned);
790 static bool write_reference_type_def(const reference_type_def_sptr&,
791 write_context&, unsigned);
792 static bool write_array_type_def(const array_type_def_sptr&,
793 write_context&, unsigned);
794 static bool write_enum_type_decl(const enum_type_decl_sptr&,
795 write_context&, unsigned);
796 static bool write_typedef_decl(const typedef_decl_sptr&,
797 write_context&, unsigned);
798 static bool write_elf_symbol(const elf_symbol_sptr&,
799 write_context&, unsigned);
800 static bool write_elf_symbols_table(const elf_symbols&,
801 write_context&, unsigned);
802 static bool write_var_decl(const var_decl_sptr&,
803 write_context&, bool, unsigned);
804 static bool write_function_decl(const function_decl_sptr&,
805 write_context&, bool, unsigned);
806 static bool write_function_type(const function_type_sptr&,
807 write_context&, unsigned);
808 static bool write_member_type_opening_tag(const type_base_sptr&,
809 write_context&, unsigned);
810 static bool write_member_type(const type_base_sptr&,
811 write_context&, unsigned);
812 static bool write_class_decl_opening_tag(const class_decl_sptr&,
813 write_context&, unsigned, bool);
814 static bool write_class_decl(const class_decl_sptr&,
815 write_context&, unsigned);
816 static bool write_union_decl_opening_tag(const union_decl_sptr&,
817 write_context&, unsigned, bool);
818 static bool write_union_decl(const union_decl_sptr&, write_context&, unsigned);
819 static bool write_type_tparameter
820 (const shared_ptr<type_tparameter>, write_context&, unsigned);
821 static bool write_non_type_tparameter
822 (const shared_ptr<non_type_tparameter>, write_context&, unsigned);
823 static bool write_template_tparameter
824 (const shared_ptr<template_tparameter>, write_context&, unsigned);
825 static bool write_type_composition
826 (const shared_ptr<type_composition>, write_context&, unsigned);
827 static bool write_template_parameter(const shared_ptr<template_parameter>,
828 write_context&, unsigned);
829 static void write_template_parameters(const shared_ptr<template_decl>,
830 write_context&, unsigned);
831 static bool write_function_tdecl
832 (const shared_ptr<function_tdecl>,
833 write_context&, unsigned);
834 static bool write_class_tdecl
835 (const shared_ptr<class_tdecl>,
836 write_context&, unsigned);
837 static void do_indent(ostream&, unsigned);
838 static void do_indent_to_level(write_context&, unsigned, unsigned);
839 static unsigned get_indent_to_level(write_context&, unsigned, unsigned);
840
841 /// Emit nb_whitespaces white spaces into the output stream.
842 void
do_indent(ostream & o,unsigned nb_whitespaces)843 do_indent(ostream& o, unsigned nb_whitespaces)
844 {
845 for (unsigned i = 0; i < nb_whitespaces; ++i)
846 o << ' ';
847 }
848
849 /// Indent initial_indent + level number of xml element indentation.
850 ///
851 /// @param ctxt the context of the parsing.
852 ///
853 /// @param initial_indent the initial number of white space to indent to.
854 ///
855 /// @param level the number of indentation level to indent to.
856 static void
do_indent_to_level(write_context & ctxt,unsigned initial_indent,unsigned level)857 do_indent_to_level(write_context& ctxt,
858 unsigned initial_indent,
859 unsigned level)
860 {
861 do_indent(ctxt.get_ostream(),
862 get_indent_to_level(ctxt, initial_indent, level));
863 }
864
865 /// Return the number of white space of indentation that
866 /// #do_indent_to_level would have used.
867 ///
868 /// @param ctxt the context of the parsing.
869 ///
870 /// @param initial_indent the initial number of white space to indent to.
871 ///
872 /// @param level the number of indentation level to indent to.
873 static unsigned
get_indent_to_level(write_context & ctxt,unsigned initial_indent,unsigned level)874 get_indent_to_level(write_context& ctxt, unsigned initial_indent,
875 unsigned level)
876 {
877 int nb_ws = initial_indent +
878 level * ctxt.get_config().get_xml_element_indent();
879 return nb_ws;
880 }
881
882 /// Annotate a declaration in form of an ABIXML comment.
883 ///
884 /// This function is further specialized for declarations and types
885 /// with special requirements.
886 ///
887 /// @tparam T shall be of type decl_base_sptr or a shared pointer to a
888 /// type derived from it, for the instantiation to be syntactically
889 /// correct.
890 ///
891 /// @param decl_sptr the shared pointer to the declaration of type T.
892 ///
893 /// @param ctxt the context of the parsing.
894 ///
895 /// @param indent the amount of white space to indent to.
896 ///
897 /// @return true iff decl is valid.
898 template <typename T>
899 static bool
annotate(const T & decl,write_context & ctxt,unsigned indent)900 annotate(const T& decl,
901 write_context& ctxt,
902 unsigned indent)
903 {
904 if (!decl)
905 return false;
906
907 if (!ctxt.get_annotate())
908 return true;
909
910 ostream& o = ctxt.get_ostream();
911
912 do_indent(o, indent);
913
914 o << "<!-- "
915 << xml::escape_xml_comment(decl->get_pretty_representation(/*internal=*/false))
916 << " -->\n";
917
918 return true;
919 }
920
921 /// Annotate an elf symbol in form of an ABIXML comment, effectively
922 /// writing out its demangled form.
923 ///
924 /// @param sym the symbol, whose name should be demangled.
925 ///
926 /// @param ctxt the context of the parsing.
927 ///
928 /// @param indent the amount of white space to indent to.
929 ///
930 /// @return true iff decl is valid
931 template<>
932 bool
annotate(const elf_symbol_sptr & sym,write_context & ctxt,unsigned indent)933 annotate(const elf_symbol_sptr& sym,
934 write_context& ctxt,
935 unsigned indent)
936 {
937 if (!sym)
938 return false;
939
940 if (!ctxt.get_annotate())
941 return true;
942
943 ostream& o = ctxt.get_ostream();
944
945 do_indent(o, indent);
946 o << "<!-- "
947 << xml::escape_xml_comment(abigail::ir::demangle_cplus_mangled_name(sym->get_name()))
948 << " -->\n";
949
950 return true;
951 }
952
953 /// Annotate a typedef declaration in form of an ABIXML comment.
954 ///
955 /// @param typedef_decl the typedef to annotate.
956 ///
957 /// @param ctxt the context of the parsing.
958 ///
959 /// @param indent the amount of white space to indent to.
960 ///
961 /// @return true iff decl is valid
962 template<>
963 bool
annotate(const typedef_decl_sptr & typedef_decl,write_context & ctxt,unsigned indent)964 annotate(const typedef_decl_sptr& typedef_decl,
965 write_context& ctxt,
966 unsigned indent)
967 {
968 if (!typedef_decl)
969 return false;
970
971 if (!ctxt.get_annotate())
972 return true;
973
974 ostream& o = ctxt.get_ostream();
975
976 do_indent(o, indent);
977
978 o << "<!-- typedef "
979 << get_type_name(typedef_decl->get_underlying_type())
980 << " "
981 << get_type_name(typedef_decl)
982 << " -->\n";
983
984 return true;
985 }
986
987 /// Annotate a function type in form of an ABIXML comment.
988 ///
989 /// @param function_type the function type to annotate.
990 ///
991 /// @param ctxt the context of the parsing.
992 ///
993 /// @param indent the amount of white space to indent to.
994 ///
995 /// @param skip_first_parm if true, do not serialize the first
996 /// parameter of the function decl.
997 //
998 /// @return true iff decl is valid
999 bool
annotate(const function_type_sptr & function_type,write_context & ctxt,unsigned indent)1000 annotate(const function_type_sptr& function_type,
1001 write_context& ctxt,
1002 unsigned indent)
1003 {
1004 if (!function_type)
1005 return false;
1006
1007 if (!ctxt.get_annotate())
1008 return true;
1009
1010 ostream& o = ctxt.get_ostream();
1011
1012 do_indent(o, indent);
1013 o << "<!-- "
1014 << xml::escape_xml_comment(get_type_name(function_type->get_return_type()))
1015 << " (";
1016
1017 vector<shared_ptr<function_decl::parameter> >::const_iterator pi =
1018 function_type->get_first_non_implicit_parm();
1019
1020 for (; pi != function_type->get_parameters().end(); ++pi)
1021 {
1022 o << xml::escape_xml_comment((*pi)->get_type_name());
1023 // emit a comma after a param type, unless it's the last one
1024 if (distance(pi, function_type->get_parameters().end()) > 1)
1025 o << ", ";
1026 }
1027 o << ") -->\n";
1028
1029 return true;
1030 }
1031
1032 /// Annotate a function declaration in form of an ABIXML comment.
1033 ///
1034 /// @param fn the function decl to annotate.
1035 ///
1036 /// @param ctxt the context of the parsing.
1037 ///
1038 /// @param indent the amount of white space to indent to.
1039 ///
1040 /// @param skip_first_parm if true, do not serialize the first
1041 /// parameter of the function decl.
1042 //
1043 /// @return true iff decl is valid
1044 static bool
annotate(const function_decl_sptr & fn,write_context & ctxt,unsigned indent)1045 annotate(const function_decl_sptr& fn,
1046 write_context& ctxt,
1047 unsigned indent)
1048 {
1049 if (!fn)
1050 return false;
1051
1052 if (!ctxt.get_annotate())
1053 return true;
1054
1055 ostream& o = ctxt.get_ostream();
1056
1057 do_indent(o, indent);
1058 o << "<!-- ";
1059
1060 if (is_member_function(fn)
1061 && (get_member_function_is_ctor(fn) || get_member_function_is_dtor(fn)))
1062 ; // we don't emit return types for ctor or dtors
1063 else
1064 o << xml::escape_xml_comment(get_type_name(fn->get_return_type()))
1065 << " ";
1066
1067 o << xml::escape_xml_comment(fn->get_qualified_name()) << "(";
1068
1069 vector<function_decl::parameter_sptr>::const_iterator pi =
1070 fn->get_first_non_implicit_parm();
1071
1072 for (; pi != fn->get_parameters().end(); ++pi)
1073 {
1074 o << xml::escape_xml_comment((*pi)->get_type_name());
1075 // emit a comma after a param type, unless it's the last one
1076 if (distance(pi, fn->get_parameters().end()) > 1)
1077 o << ", ";
1078 }
1079 o << ") -->\n";
1080
1081 return true;
1082 }
1083
1084 /// Annotate a function parameter in form of an ABIXML comment.
1085 ///
1086 /// @param parm the function parameter to annotate.
1087 ///
1088 /// @param ctxt the context of the parsing.
1089 ///
1090 /// @param indent the amount of white space to indent to.
1091 ///
1092 /// @return true iff decl is valid
1093 template<>
1094 bool
annotate(const function_decl::parameter_sptr & parm,write_context & ctxt,unsigned indent)1095 annotate(const function_decl::parameter_sptr& parm,
1096 write_context& ctxt,
1097 unsigned indent)
1098 {
1099 if (!parm)
1100 return false;
1101
1102 if (!ctxt.get_annotate())
1103 return true;
1104
1105 ostream &o = ctxt.get_ostream();
1106
1107 do_indent(o, indent);
1108
1109 o << "<!-- ";
1110
1111 if (parm->get_variadic_marker())
1112 o << "variadic parameter";
1113 else
1114 {
1115 if (parm->get_is_artificial())
1116 {
1117 if (parm->get_index() == 0)
1118 o << "implicit ";
1119 else
1120 o << "artificial ";
1121 }
1122 o << "parameter of type '"
1123 << xml::escape_xml_comment(get_pretty_representation(parm->get_type()));
1124 }
1125
1126 o << "' -->\n";
1127
1128 return true;
1129 }
1130
1131 /// Write a location to the output stream.
1132 ///
1133 /// If the location is empty, nothing is written.
1134 ///
1135 /// @param loc the location to consider.
1136 ///
1137 /// @param tu the translation unit the location belongs to.
1138 ///
1139 /// @param ctxt the writer context to use.
1140 static void
write_location(const location & loc,write_context & ctxt)1141 write_location(const location& loc, write_context& ctxt)
1142 {
1143 if (!loc || loc.get_is_artificial())
1144 return;
1145
1146 if (!ctxt.get_show_locs())
1147 return;
1148
1149 string filepath;
1150 unsigned line = 0, column = 0;
1151
1152 loc.expand(filepath, line, column);
1153
1154 ostream &o = ctxt.get_ostream();
1155
1156 if (ctxt.get_short_locs())
1157 tools_utils::base_name(filepath, filepath);
1158
1159 o << " filepath='" << xml::escape_xml_string(filepath) << "'"
1160 << " line='" << line << "'"
1161 << " column='" << column << "'";
1162 }
1163
1164 /// Write the location of a decl to the output stream.
1165 ///
1166 /// If the location is empty, nothing is written.
1167 ///
1168 /// @param decl the decl to consider.
1169 ///
1170 /// @param ctxt the @ref writer_context to use.
1171 static void
write_location(const decl_base_sptr & decl,write_context & ctxt)1172 write_location(const decl_base_sptr& decl,
1173 write_context& ctxt)
1174 {
1175 if (!decl)
1176 return;
1177
1178 location loc = decl->get_location();
1179 if (!loc)
1180 return;
1181
1182 write_location(loc, ctxt);
1183 }
1184
1185 /// Serialize the visibility property of the current decl as the
1186 /// 'visibility' attribute for the current xml element.
1187 ///
1188 /// @param decl the instance of decl_base to consider.
1189 ///
1190 /// @param o the output stream to serialize the property to.
1191 ///
1192 /// @return true upon successful completion, false otherwise.
1193 static bool
write_visibility(const shared_ptr<decl_base> & decl,ostream & o)1194 write_visibility(const shared_ptr<decl_base>& decl, ostream& o)
1195 {
1196 if (!decl)
1197 return false;
1198
1199 decl_base::visibility v = decl->get_visibility();
1200 string str;
1201
1202 switch (v)
1203 {
1204 case decl_base::VISIBILITY_NONE:
1205 return true;
1206 case decl_base::VISIBILITY_DEFAULT:
1207 str = "default";
1208 break;
1209 case decl_base::VISIBILITY_PROTECTED:
1210 str = "protected";
1211 break;
1212 case decl_base::VISIBILITY_HIDDEN:
1213 str = "hidden";
1214 break;
1215 case decl_base::VISIBILITY_INTERNAL:
1216 str = "internal";
1217 break;
1218 }
1219
1220 if (str.empty())
1221 return false;
1222
1223 o << " visibility='" << str << "'";
1224
1225 return true;
1226 }
1227
1228 /// Serialize the 'binding' property of the current decl.
1229 ///
1230 /// @param decl the decl to consider.
1231 ///
1232 /// @param o the output stream to serialize the property to.
1233 static bool
write_binding(const shared_ptr<decl_base> & decl,ostream & o)1234 write_binding(const shared_ptr<decl_base>& decl, ostream& o)
1235 {
1236 if (!decl)
1237 return false;
1238
1239 decl_base::binding bind = decl_base::BINDING_NONE;
1240
1241 shared_ptr<var_decl> var =
1242 dynamic_pointer_cast<var_decl>(decl);
1243 if (var)
1244 bind = var->get_binding();
1245 else
1246 {
1247 shared_ptr<function_decl> fun =
1248 dynamic_pointer_cast<function_decl>(decl);
1249 if (fun)
1250 bind = fun->get_binding();
1251 }
1252
1253 string str;
1254 switch (bind)
1255 {
1256 case decl_base::BINDING_NONE:
1257 break;
1258 case decl_base::BINDING_LOCAL:
1259 str = "local";
1260 break;
1261 case decl_base::BINDING_GLOBAL:
1262 str = "global";
1263 break;
1264 case decl_base::BINDING_WEAK:
1265 str = "weak";
1266 break;
1267 }
1268
1269 if (!str.empty())
1270 o << " binding='" << str << "'";
1271
1272 return true;
1273 }
1274
1275 /// Write the "is-artificial" attribute of the @ref decl.
1276 ///
1277 /// @param decl the declaration to consider.
1278 ///
1279 /// @param o the output stream to emit the "is-artificial" attribute
1280 /// to.
1281 ///
1282 /// @return true iff the "is-artificial" attribute was emitted.
1283 static bool
write_is_artificial(const decl_base_sptr & decl,ostream & o)1284 write_is_artificial(const decl_base_sptr& decl, ostream& o)
1285 {
1286 if (!decl)
1287 return false;
1288
1289 if (decl->get_is_artificial())
1290 o << " is-artificial='yes'";
1291
1292 return true;
1293 }
1294
1295 /// Write the 'is-non-reachable' attribute if a given type we are
1296 /// looking at is not reachable from global functions and variables
1297 /// and if the user asked us to track that information.
1298 ///
1299 /// @param t the type to consider.
1300 ///
1301 /// @param o the output stream to write the 'is-non-reachable'
1302 /// attribute to.
1303 static bool
write_is_non_reachable(const type_base_sptr & t,ostream & o)1304 write_is_non_reachable(const type_base_sptr& t, ostream& o)
1305 {
1306 if (!t)
1307 return false;
1308
1309 corpus* c = t->get_corpus();
1310 if (!c)
1311 return false;
1312
1313 if (!c->recording_types_reachable_from_public_interface_supported()
1314 || c->type_is_reachable_from_public_interfaces(*t))
1315 return false;
1316
1317 o << " is-non-reachable='yes'";
1318
1319 return true;
1320 }
1321
1322 /// Write the 'tracking-non-reachable-types' attribute if for a given
1323 /// corpus, the user wants us to track non-reachable types.
1324 ///
1325 /// @param corpus the ABI corpus to consider.
1326 ///
1327 /// @param o the output parameter to write the
1328 /// 'tracking-non-reachable-types' attribute to.
1329 static bool
write_tracking_non_reachable_types(const corpus_sptr & corpus,ostream & o)1330 write_tracking_non_reachable_types(const corpus_sptr& corpus,
1331 ostream& o)
1332 {
1333 corpus_group* group = corpus->get_group();
1334 if (!group)
1335 if (corpus->recording_types_reachable_from_public_interface_supported())
1336 {
1337 o << " tracking-non-reachable-types='yes'";
1338 return true;
1339 }
1340
1341 return false;
1342 }
1343
1344 /// Serialize the size and alignment attributes of a given type.
1345 ///
1346 /// @param decl the type to consider.
1347 ///
1348 /// @param o the output stream to serialize to.
1349 ///
1350 /// @param default_size size in bits that is the default for the type.
1351 /// No size-in-bits attribute is written if it
1352 /// would be the default value.
1353 ///
1354 /// @param default_alignment alignment in bits that is the default for
1355 /// the type. No alignment-in-bits attribute is
1356 /// written if it would be the default value.
1357 static void
write_size_and_alignment(const shared_ptr<type_base> decl,ostream & o,size_t default_size,size_t default_alignment)1358 write_size_and_alignment(const shared_ptr<type_base> decl, ostream& o,
1359 size_t default_size, size_t default_alignment)
1360 {
1361 size_t size_in_bits = decl->get_size_in_bits();
1362 if (size_in_bits != default_size)
1363 o << " size-in-bits='" << size_in_bits << "'";
1364
1365 size_t alignment_in_bits = decl->get_alignment_in_bits();
1366 if (alignment_in_bits != default_alignment)
1367 o << " alignment-in-bits='" << alignment_in_bits << "'";
1368 }
1369
1370 /// Serialize the size and alignment attributes of a given type.
1371 /// @param decl the type to consider.
1372 ///
1373 /// @param o the output stream to serialize to.
1374 static void
write_array_size_and_alignment(const shared_ptr<array_type_def> decl,ostream & o)1375 write_array_size_and_alignment(const shared_ptr<array_type_def> decl, ostream& o)
1376 {
1377 if (decl->is_infinite())
1378 o << " size-in-bits='" << "infinite" << "'";
1379 else {
1380 size_t size_in_bits = decl->get_size_in_bits();
1381 if (size_in_bits)
1382 o << " size-in-bits='" << size_in_bits << "'";
1383 }
1384
1385 size_t alignment_in_bits = decl->get_alignment_in_bits();
1386 if (alignment_in_bits)
1387 o << " alignment-in-bits='" << alignment_in_bits << "'";
1388 }
1389 /// Serialize the access specifier.
1390 ///
1391 /// @param a the access specifier to serialize.
1392 ///
1393 /// @param o the output stream to serialize it to.
1394 static void
write_access(access_specifier a,ostream & o)1395 write_access(access_specifier a, ostream& o)
1396 {
1397 string access_str = "private";
1398
1399 switch (a)
1400 {
1401 case private_access:
1402 access_str = "private";
1403 break;
1404
1405 case protected_access:
1406 access_str = "protected";
1407 break;
1408
1409 case public_access:
1410 access_str = "public";
1411 break;
1412
1413 default:
1414 break;
1415 }
1416
1417 o << " access='" << access_str << "'";
1418 }
1419
1420 /// Serialize the layout offset of a data member.
1421 static void
write_layout_offset(var_decl_sptr member,ostream & o)1422 write_layout_offset(var_decl_sptr member, ostream& o)
1423 {
1424 if (!is_data_member(member))
1425 return;
1426
1427 if (get_data_member_is_laid_out(member))
1428 o << " layout-offset-in-bits='"
1429 << get_data_member_offset(member)
1430 << "'";
1431 }
1432
1433 /// Serialize the layout offset of a base class
1434 static void
write_layout_offset(shared_ptr<class_decl::base_spec> base,ostream & o)1435 write_layout_offset(shared_ptr<class_decl::base_spec> base, ostream& o)
1436 {
1437 if (!base)
1438 return;
1439
1440 if (base->get_offset_in_bits() >= 0)
1441 o << " layout-offset-in-bits='" << base->get_offset_in_bits() << "'";
1442 }
1443
1444 /// Serialize the access specifier of a class member.
1445 ///
1446 /// @param member a pointer to the class member to consider.
1447 ///
1448 /// @param o the ostream to serialize the member to.
1449 static void
write_access(decl_base_sptr member,ostream & o)1450 write_access(decl_base_sptr member, ostream& o)
1451 {write_access(get_member_access_specifier(member), o);}
1452
1453 /// Write the voffset of a member function if it's non-zero
1454 ///
1455 /// @param fn the member function to consider
1456 ///
1457 /// @param o the output stream to write to
1458 static void
write_voffset(function_decl_sptr fn,ostream & o)1459 write_voffset(function_decl_sptr fn, ostream&o)
1460 {
1461 if (!fn)
1462 return;
1463
1464 if (get_member_function_is_virtual(fn))
1465 {
1466 ssize_t voffset = get_member_function_vtable_offset(fn);
1467 o << " vtable-offset='" << voffset << "'";
1468 }
1469 }
1470
1471 /// Serialize an elf_symbol::type into an XML node attribute named
1472 /// 'type'.
1473 ///
1474 /// @param t the elf_symbol::type to serialize.
1475 ///
1476 /// @param o the output stream to serialize it to.
1477 static void
write_elf_symbol_type(elf_symbol::type t,ostream & o)1478 write_elf_symbol_type(elf_symbol::type t, ostream& o)
1479 {
1480 string repr;
1481
1482 switch (t)
1483 {
1484 case elf_symbol::NOTYPE_TYPE:
1485 repr = "no-type";
1486 break;
1487 case elf_symbol::OBJECT_TYPE:
1488 repr = "object-type";
1489 break;
1490 case elf_symbol::FUNC_TYPE:
1491 repr = "func-type";
1492 break;
1493 case elf_symbol::SECTION_TYPE:
1494 repr = "section-type";
1495 break;
1496 case elf_symbol::FILE_TYPE:
1497 repr = "file-type";
1498 break;
1499 case elf_symbol::COMMON_TYPE:
1500 repr = "common-type";
1501 break;
1502 case elf_symbol::TLS_TYPE:
1503 repr = "tls-type";
1504 break;
1505 case elf_symbol::GNU_IFUNC_TYPE:
1506 repr = "gnu-ifunc-type";
1507 break;
1508 default:
1509 repr = "no-type";
1510 break;
1511 }
1512
1513 o << " type='" << repr << "'";
1514 }
1515
1516 /// Serialize an elf_symbol::binding into an XML element attribute of
1517 /// name 'binding'.
1518 ///
1519 /// @param b the elf_symbol::binding to serialize.
1520 ///
1521 /// @param o the output stream to serialize the binding to.
1522 static void
write_elf_symbol_binding(elf_symbol::binding b,ostream & o)1523 write_elf_symbol_binding(elf_symbol::binding b, ostream& o)
1524 {
1525 string repr;
1526
1527 switch (b)
1528 {
1529 case elf_symbol::LOCAL_BINDING:
1530 repr = "local-binding";
1531 break;
1532 case elf_symbol::GLOBAL_BINDING:
1533 repr = "global-binding";
1534 break;
1535 case elf_symbol::WEAK_BINDING:
1536 repr = "weak-binding";
1537 break;
1538 case elf_symbol::GNU_UNIQUE_BINDING:
1539 repr = "gnu-unique-binding";
1540 break;
1541 default:
1542 repr = "no-binding";
1543 break;
1544 }
1545
1546 o << " binding='" << repr << "'";
1547 }
1548
1549 /// Serialize an elf_symbol::binding into an XML element attribute of
1550 /// name 'binding'.
1551 ///
1552 /// @param b the elf_symbol::binding to serialize.
1553 ///
1554 /// @param o the output stream to serialize the binding to.
1555 static void
write_elf_symbol_visibility(elf_symbol::visibility v,ostream & o)1556 write_elf_symbol_visibility(elf_symbol::visibility v, ostream& o)
1557 {
1558 string repr;
1559
1560 switch (v)
1561 {
1562 case elf_symbol::DEFAULT_VISIBILITY:
1563 repr = "default-visibility";
1564 break;
1565 case elf_symbol::PROTECTED_VISIBILITY:
1566 repr = "protected-visibility";
1567 break;
1568 case elf_symbol::HIDDEN_VISIBILITY:
1569 repr = "hidden-visibility";
1570 break;
1571 case elf_symbol::INTERNAL_VISIBILITY:
1572 repr = "internal-visibility";
1573 break;
1574 default:
1575 repr = "default-visibility";
1576 break;
1577 }
1578
1579 o << " visibility='" << repr << "'";
1580 }
1581
1582 /// Write alias attributes for the aliases of a given symbol.
1583 ///
1584 /// @param sym the symbol to write the attributes for.
1585 ///
1586 /// @param o the output stream to write the attributes to.
1587 ///
1588 /// @return true upon successful completion.
1589 static bool
write_elf_symbol_aliases(const elf_symbol & sym,ostream & out)1590 write_elf_symbol_aliases(const elf_symbol& sym, ostream& out)
1591 {
1592 if (!sym.is_main_symbol() || !sym.has_aliases())
1593 return false;
1594
1595
1596 std::vector<std::string> aliases;
1597 for (elf_symbol_sptr s = sym.get_next_alias(); s && !s->is_main_symbol();
1598 s = s->get_next_alias())
1599 {
1600 if (!s->is_public())
1601 continue;
1602
1603 if (s->is_suppressed())
1604 continue;
1605
1606 if (sym.is_in_ksymtab() != s->is_in_ksymtab())
1607 continue;
1608
1609 aliases.push_back(s->get_id_string());
1610 }
1611
1612 if (!aliases.empty())
1613 {
1614 out << " alias='";
1615 std::string separator;
1616 for (const auto& alias : aliases)
1617 {
1618 out << separator << alias;
1619 separator = ",";
1620 }
1621
1622 out << "'";
1623 return true;
1624 }
1625
1626 return false;
1627 }
1628
1629 /// Write an XML attribute for the reference to a symbol for the
1630 /// current decl.
1631 ///
1632 /// @param sym the symbol to consider.
1633 ///
1634 /// @param o the output stream to write the attribute to.
1635 ///
1636 /// @return true upon successful completion.
1637 static bool
write_elf_symbol_reference(const elf_symbol & sym,ostream & o)1638 write_elf_symbol_reference(const elf_symbol& sym, ostream& o)
1639 {
1640 const elf_symbol* main = sym.get_main_symbol().get();
1641 const elf_symbol* alias = &sym;
1642 bool found = !alias->is_suppressed();
1643 // If the symbol itself is suppressed, check the alias chain.
1644 if (!found)
1645 {
1646 alias = main;
1647 found = !alias->is_suppressed();
1648 }
1649 // If the main symbol is suppressed, search the remainder of the chain.
1650 while (!found)
1651 {
1652 alias = alias->get_next_alias().get();
1653 // Two separate termination conditions at present.
1654 if (!alias || alias == main)
1655 break;
1656 found = !alias->is_suppressed();
1657 }
1658 // If all aliases are suppressed, just stick with the main symbol.
1659 if (!found)
1660 alias = main;
1661 o << " elf-symbol-id='" << alias->get_id_string() << "'";
1662 return true;
1663 }
1664
1665 /// Write an XML attribute for the reference to a symbol for the
1666 /// current decl.
1667 ///
1668 /// @param sym the symbol to consider.
1669 ///
1670 /// @param o the output stream to write the attribute to.
1671 ///
1672 /// @return true upon successful completion.
1673 static bool
write_elf_symbol_reference(const elf_symbol_sptr sym,ostream & o)1674 write_elf_symbol_reference(const elf_symbol_sptr sym, ostream& o)
1675 {
1676 if (!sym)
1677 return false;
1678
1679 return write_elf_symbol_reference(*sym, o);
1680 }
1681
1682 /// Serialize the attributes "constructor", "destructor" or "static"
1683 /// if they have true value.
1684 ///
1685 /// @param is_ctor if set to true, the "constructor='true'" string is
1686 /// emitted.
1687 ///
1688 /// @param is_dtor if set to true the "destructor='true' string is
1689 /// emitted.
1690 ///
1691 /// @param is_static if set to true the "static='true'" string is
1692 /// emitted.
1693 ///
1694 /// @param o the output stream to use for the serialization.
1695 static void
write_cdtor_const_static(bool is_ctor,bool is_dtor,bool is_const,bool is_static,ostream & o)1696 write_cdtor_const_static(bool is_ctor,
1697 bool is_dtor,
1698 bool is_const,
1699 bool is_static,
1700 ostream& o)
1701 {
1702 if (is_static)
1703 o << " static='yes'";
1704 if (is_ctor)
1705 o << " constructor='yes'";
1706 else if (is_dtor)
1707 o << " destructor='yes'";
1708 if (is_const)
1709 o << " const='yes'";
1710 }
1711
1712 /// Serialize the attribute "is-declaration-only", if the
1713 /// decl_base_sptr has its 'is_declaration_only property set.
1714 ///
1715 /// @param t the pointer to instance of @ref decl_base to consider.
1716 ///
1717 /// @param o the output stream to serialize to.
1718 static void
write_is_declaration_only(const decl_base_sptr & d,ostream & o)1719 write_is_declaration_only(const decl_base_sptr& d, ostream& o)
1720 {
1721 if (d->get_is_declaration_only())
1722 o << " is-declaration-only='yes'";
1723 }
1724
1725 /// Serialize the attribute "is-struct", if the current instance of
1726 /// class_decl is a struct.
1727 ///
1728 /// @param klass a pointer to the instance of class_decl to consider.
1729 ///
1730 /// @param o the output stream to serialize to.
1731 static void
write_is_struct(const class_decl_sptr & klass,ostream & o)1732 write_is_struct(const class_decl_sptr& klass, ostream& o)
1733 {
1734 if (klass->is_struct())
1735 o << " is-struct='yes'";
1736 }
1737
1738 /// Serialize the attribute "is-anonymous", if the current instance of
1739 /// decl is anonymous
1740 ///
1741 /// @param dcl a pointer to the instance of @ref decl_base to consider.
1742 ///
1743 /// @param o the output stream to serialize to.
1744 static void
write_is_anonymous(const decl_base_sptr & decl,ostream & o)1745 write_is_anonymous(const decl_base_sptr& decl, ostream& o)
1746 {
1747 if (decl->get_is_anonymous())
1748 o << " is-anonymous='yes'";
1749 }
1750
1751 /// Serialize the "naming-typedef-id" attribute, if the current
1752 /// instance of @ref class_decl has a naming typedef.
1753 ///
1754 /// @param klass the @ref class_decl to consider.
1755 ///
1756 /// @param ctxt the write context to use.
1757 static void
write_naming_typedef(const decl_base_sptr & decl,write_context & ctxt)1758 write_naming_typedef(const decl_base_sptr& decl, write_context& ctxt)
1759 {
1760 if (!decl)
1761 return;
1762
1763 ostream &o = ctxt.get_ostream();
1764
1765 if (typedef_decl_sptr typedef_type = decl->get_naming_typedef())
1766 {
1767 o << " naming-typedef-id='" << ctxt.get_id_for_type(typedef_type) << "'";
1768 ctxt.record_type_as_referenced(typedef_type);
1769 }
1770 }
1771
1772 /// Helper to serialize a type artifact.
1773 ///
1774 /// @param type the type to serialize.
1775 ///
1776 /// @param ctxt the @ref write_context to use.
1777 ///
1778 /// @param indent the number of white space to use for indentation.
1779 ///
1780 /// @return true upon successful completion.
1781 static bool
write_type(const type_base_sptr & type,write_context & ctxt,unsigned indent)1782 write_type(const type_base_sptr& type, write_context& ctxt, unsigned indent)
1783 {
1784 if (write_type_decl(dynamic_pointer_cast<type_decl> (type),
1785 ctxt, indent)
1786 || write_qualified_type_def (dynamic_pointer_cast<qualified_type_def>
1787 (type),
1788 ctxt, indent)
1789 || write_pointer_type_def(dynamic_pointer_cast<pointer_type_def>(type),
1790 ctxt, indent)
1791 || write_reference_type_def(dynamic_pointer_cast
1792 <reference_type_def>(type), ctxt, indent)
1793 || write_array_type_def(dynamic_pointer_cast
1794 <array_type_def>(type), ctxt, indent)
1795 || write_enum_type_decl(dynamic_pointer_cast<enum_type_decl>(type),
1796 ctxt, indent)
1797 || write_typedef_decl(dynamic_pointer_cast<typedef_decl>(type),
1798 ctxt, indent)
1799 || write_class_decl(is_class_type(type), ctxt, indent)
1800 || write_union_decl(is_union_type(type), ctxt, indent)
1801 || (write_function_tdecl
1802 (dynamic_pointer_cast<function_tdecl>(type), ctxt, indent))
1803 || (write_class_tdecl
1804 (dynamic_pointer_cast<class_tdecl>(type), ctxt, indent)))
1805 return true;
1806
1807 return false;
1808 }
1809
1810 /// Serialize a pointer to an of decl_base into an output stream.
1811 ///
1812 /// @param decl the pointer to decl_base to serialize
1813 ///
1814 /// @param ctxt the context of the serialization. It contains e.g, the
1815 /// output stream to serialize to.
1816 ///
1817 /// @param indent how many indentation spaces to use during the
1818 /// serialization.
1819 ///
1820 /// @return true upon successful completion, false otherwise.
1821 static bool
write_decl(const decl_base_sptr & decl,write_context & ctxt,unsigned indent)1822 write_decl(const decl_base_sptr& decl, write_context& ctxt, unsigned indent)
1823 {
1824 if (write_type_decl(dynamic_pointer_cast<type_decl> (decl),
1825 ctxt, indent)
1826 || write_namespace_decl(dynamic_pointer_cast<namespace_decl>(decl),
1827 ctxt, indent)
1828 || write_qualified_type_def (dynamic_pointer_cast<qualified_type_def>
1829 (decl),
1830 ctxt, indent)
1831 || write_pointer_type_def(dynamic_pointer_cast<pointer_type_def>(decl),
1832 ctxt, indent)
1833 || write_reference_type_def(dynamic_pointer_cast
1834 <reference_type_def>(decl), ctxt, indent)
1835 || write_array_type_def(dynamic_pointer_cast
1836 <array_type_def>(decl), ctxt, indent)
1837 || write_enum_type_decl(dynamic_pointer_cast<enum_type_decl>(decl),
1838 ctxt, indent)
1839 || write_typedef_decl(dynamic_pointer_cast<typedef_decl>(decl),
1840 ctxt, indent)
1841 || write_var_decl(dynamic_pointer_cast<var_decl>(decl), ctxt,
1842 /*write_linkage_name=*/true, indent)
1843 || write_function_decl(dynamic_pointer_cast<method_decl>
1844 (decl), ctxt, /*skip_first_parameter=*/true,
1845 indent)
1846 || write_function_decl(dynamic_pointer_cast<function_decl>(decl),
1847 ctxt, /*skip_first_parameter=*/false, indent)
1848 || write_class_decl(is_class_type(decl), ctxt, indent)
1849 || write_union_decl(is_union_type(decl), ctxt, indent)
1850 || (write_function_tdecl
1851 (dynamic_pointer_cast<function_tdecl>(decl), ctxt, indent))
1852 || (write_class_tdecl
1853 (dynamic_pointer_cast<class_tdecl>(decl), ctxt, indent)))
1854 return true;
1855
1856 return false;
1857 }
1858
1859 /// Emit a declaration, along with its scope.
1860 ///
1861 /// This function is called at the end of emitting a translation unit,
1862 /// to emit type declarations that were referenced by types that were
1863 /// emitted in the TU already, but that were not emitted themselves.
1864 ///
1865 /// @param decl the decl to emit.
1866 ///
1867 /// @param ctxt the write context to use.
1868 ///
1869 /// @param initial_indent the number of indentation spaces to use.
1870 static void
write_decl_in_scope(const decl_base_sptr & decl,write_context & ctxt,unsigned initial_indent)1871 write_decl_in_scope(const decl_base_sptr& decl,
1872 write_context& ctxt,
1873 unsigned initial_indent)
1874 {
1875 type_base_sptr type = is_type(decl);
1876 ABG_ASSERT(type);
1877
1878 if (ctxt.type_is_emitted(type))
1879 return;
1880
1881 list<scope_decl*> scopes;
1882 for (scope_decl* s = decl->get_scope();
1883 s && !is_global_scope(s);
1884 s = s->get_scope())
1885 scopes.push_front(s);
1886
1887 ostream& o = ctxt.get_ostream();
1888 const config& c = ctxt.get_config();
1889 stack<string> closing_tags;
1890 stack<unsigned> closing_indents;
1891 unsigned indent = initial_indent;
1892 for (list<scope_decl*>::const_iterator i = scopes.begin();
1893 i != scopes.end();
1894 ++i)
1895 {
1896 ABG_ASSERT(!is_global_scope(*i));
1897
1898 // A type scope is either a namespace ...
1899 if (namespace_decl* n = is_namespace(*i))
1900 {
1901 do_indent(o, indent);
1902 o << "<namespace-decl name='"
1903 << xml::escape_xml_string(n->get_name())
1904 << "'>\n";
1905 closing_tags.push("</namespace-decl>");
1906 closing_indents.push(indent);
1907 }
1908 // ... or a class.
1909 else if (class_decl* c = is_class_type(*i))
1910 {
1911 class_decl_sptr class_type(c, noop_deleter());
1912 write_class_decl_opening_tag(class_type, ctxt, indent,
1913 /*prepare_to_handle_members=*/false);
1914 closing_tags.push("</class-decl>");
1915 closing_indents.push(indent);
1916
1917 unsigned nb_ws = get_indent_to_level(ctxt, indent, 1);
1918 write_member_type_opening_tag(type, ctxt, nb_ws);
1919 indent = nb_ws;
1920 closing_tags.push("</member-type>");
1921 closing_indents.push(nb_ws);
1922 }
1923 else if (union_decl *u = is_union_type(*i))
1924 {
1925 union_decl_sptr union_type(u, noop_deleter());
1926 write_union_decl_opening_tag(union_type, ctxt, indent,
1927 /*prepare_to_handle_members=*/false);
1928 closing_tags.push("</union-decl>");
1929 closing_indents.push(indent);
1930
1931 unsigned nb_ws = get_indent_to_level(ctxt, indent, 1);
1932 write_member_type_opening_tag(type, ctxt, nb_ws);
1933 indent = nb_ws;
1934 closing_tags.push("</member-type>");
1935 closing_indents.push(nb_ws);
1936 }
1937 else
1938 // We should never reach this point.
1939 abort();
1940 indent += c.get_xml_element_indent();
1941 }
1942
1943 write_decl(decl, ctxt, indent);
1944
1945 while (!closing_tags.empty())
1946 {
1947 do_indent(o, closing_indents.top());
1948 o << closing_tags.top() << "\n";
1949 closing_tags.pop();
1950 closing_indents.pop();
1951 }
1952 }
1953
1954 /// Create a @ref write_context object that can be used to emit abixml
1955 /// files.
1956 ///
1957 /// @param env the environment for the @ref write_context object to use.
1958 ///
1959 /// @param default_output_stream the default output stream to use.
1960 ///
1961 /// @return the new @ref write_context object.
1962 write_context_sptr
create_write_context(const environment * env,ostream & default_output_stream)1963 create_write_context(const environment *env,
1964 ostream& default_output_stream)
1965 {
1966 write_context_sptr ctxt(new write_context(env, default_output_stream));
1967 return ctxt;
1968 }
1969
1970 /// Set the "show-locs" flag.
1971 ///
1972 /// When this flag is set then the XML writer emits location (///
1973 /// information (file name, line and column) for the ABI artifacts
1974 /// that it emits.
1975 ///
1976 /// @param ctxt the @ref write_context to set the option for.
1977 ///
1978 /// @param flag the new value of the option.
1979 void
set_show_locs(write_context & ctxt,bool flag)1980 set_show_locs(write_context& ctxt, bool flag)
1981 {ctxt.set_show_locs(flag);}
1982
1983 /// Set the 'annotate' flag.
1984 ///
1985 /// When this flag is set then the XML writer annotates ABI artifacts
1986 /// with a human readable description.
1987 ///
1988 /// @param ctxt the context to set this flag on to.
1989 ///
1990 /// @param flag the new value of the 'annotate' flag.
1991 void
set_annotate(write_context & ctxt,bool flag)1992 set_annotate(write_context& ctxt, bool flag)
1993 {ctxt.set_annotate(flag);}
1994
1995 /// Set the new ostream.
1996 ///
1997 /// The ostream refers to the object, writers should stream new output to.
1998 ///
1999 /// @param ctxt the context to set this to.
2000 ///
2001 /// @param os the new ostream
2002 void
set_ostream(write_context & ctxt,ostream & os)2003 set_ostream(write_context& ctxt, ostream& os)
2004 {ctxt.set_ostream(os);}
2005
2006 /// Set the 'write-architecture' flag.
2007 ///
2008 /// When this flag is set then the XML writer will emit architecture
2009 /// information
2010 ///
2011 /// @param ctxt the context to set this flag on to.
2012 ///
2013 /// @param flag the new value of the 'write-architecture' flag.
2014 void
set_write_architecture(write_context & ctxt,bool flag)2015 set_write_architecture(write_context& ctxt, bool flag)
2016 {ctxt.set_write_architecture(flag);}
2017
2018 /// Set the 'write-corpus-path' flag.
2019 ///
2020 /// When this flag is set then the XML writer will emit corpus-path
2021 /// information
2022 ///
2023 /// @param ctxt the context to set this flag on to.
2024 ///
2025 /// @param flag the new value of the 'write-corpus-path' flag.
2026 void
set_write_corpus_path(write_context & ctxt,bool flag)2027 set_write_corpus_path(write_context& ctxt, bool flag)
2028 {ctxt.set_write_corpus_path(flag);}
2029
2030 /// Set the 'write-comp-dir' flag.
2031 ///
2032 /// When this flag is set then the XML writer will emit compilation dir
2033 /// information
2034 ///
2035 /// @param ctxt the context to set this flag on to.
2036 ///
2037 /// @param flag the new value of the 'write-comp-dir' flag.
2038 void
set_write_comp_dir(write_context & ctxt,bool flag)2039 set_write_comp_dir(write_context& ctxt, bool flag)
2040 {ctxt.set_write_comp_dir(flag);}
2041
2042 /// Set the 'short-locs' flag.
2043 ///
2044 /// When this flag is set then the XML writer will emit only file names
2045 /// rather than full paths.
2046 ///
2047 /// @param ctxt the context to set this flag on to.
2048 ///
2049 /// @param flag the new value of the 'short-locs' flag.
2050 void
set_short_locs(write_context & ctxt,bool flag)2051 set_short_locs(write_context& ctxt, bool flag)
2052 {ctxt.set_short_locs(flag);}
2053
2054 /// Set the 'parameter-names' flag.
2055 ///
2056 /// When this flag is set then the XML writer will emit the names of
2057 /// function parameters.
2058 ///
2059 /// @param ctxt the context to set this flag on to.
2060 ///
2061 /// @param flag the new value of the 'parameter-names' flag.
2062 void
set_write_parameter_names(write_context & ctxt,bool flag)2063 set_write_parameter_names(write_context& ctxt, bool flag)
2064 {ctxt.set_write_parameter_names(flag);}
2065
2066 /// Set the 'elf-needed' flag.
2067 ///
2068 /// When this flag is set then the XML writer will emit corpus
2069 /// get_needed() (DT_NEEDED) information.
2070 ///
2071 /// @param ctxt the context to set this flag on to.
2072 ///
2073 /// @param flag the new value of the 'elf-needed' flag.
2074 void
set_write_elf_needed(write_context & ctxt,bool flag)2075 set_write_elf_needed(write_context& ctxt, bool flag)
2076 {ctxt.set_write_elf_needed(flag);}
2077
2078 /// Set the 'default-sizes' flag.
2079 ///
2080 /// When this flag is set then the XML writer will emit default
2081 /// size-in-bits attributes for pointer type definitions, reference
2082 /// type definitions, function declarations and function types even
2083 /// when they are equal to the default address size of the translation
2084 /// unit.
2085 ///
2086 /// @param ctxt the context to set this flag on to.
2087 ///
2088 /// @param flag the new value of the 'default-sizes' flag.
2089 void
set_write_default_sizes(write_context & ctxt,bool flag)2090 set_write_default_sizes(write_context& ctxt, bool flag)
2091 {ctxt.set_write_default_sizes(flag);}
2092
2093 /// Set the 'type-id-style' property.
2094 ///
2095 /// This property controls the kind of type ids used in XML output.
2096 ///
2097 /// @param ctxt the context to set this property on.
2098 ///
2099 /// @param style the new value of the 'type-id-style' property.
2100 void
set_type_id_style(write_context & ctxt,type_id_style_kind style)2101 set_type_id_style(write_context& ctxt, type_id_style_kind style)
2102 {ctxt.set_type_id_style(style);}
2103
2104 /// Serialize the canonical types of a given scope.
2105 ///
2106 /// @param scope the scope to consider.
2107 ///
2108 /// @param ctxt the write context to use.
2109 ///
2110 /// @param indent the number of white space indentation to use.
2111 //
2112 // @param is_member_type if true, the canonical types are emitted as
2113 // member types (of a class).
2114 //
2115 // return true upon successful completion.
2116 static bool
write_canonical_types_of_scope(const scope_decl & scope,write_context & ctxt,const unsigned indent,bool is_member_type=false)2117 write_canonical_types_of_scope(const scope_decl &scope,
2118 write_context &ctxt,
2119 const unsigned indent,
2120 bool is_member_type = false)
2121 {
2122 const type_base_sptrs_type &canonical_types =
2123 scope.get_sorted_canonical_types();
2124
2125 for (type_base_sptrs_type::const_iterator i = canonical_types.begin();
2126 i != canonical_types.end();
2127 ++i)
2128 {
2129 if (is_member_type)
2130 write_member_type(*i, ctxt, indent);
2131 else
2132 write_type(*i, ctxt, indent);
2133 }
2134
2135 return true;
2136 }
2137
2138 /// Test if a type referenced in a given translation unit should be
2139 /// emitted or not.
2140 ///
2141 /// This is a subroutine of @ref write_translation_unit.
2142 ///
2143 /// @param t the type to consider.
2144 ///
2145 /// @param ctxt the write context to consider.
2146 ///
2147 /// @param tu the translation unit to consider.
2148 ///
2149 /// @param tu_is_last true if @p tu is the last translation unit being
2150 /// emitted.
2151 ///
2152 /// @return true iff @p t is to be emitted.
2153 static bool
referenced_type_should_be_emitted(const type_base * t,const write_context & ctxt,const translation_unit & tu,bool tu_is_last)2154 referenced_type_should_be_emitted(const type_base *t,
2155 const write_context& ctxt,
2156 const translation_unit& tu,
2157 bool tu_is_last)
2158 {
2159 if ((tu_is_last || (t->get_translation_unit()
2160 && (t->get_translation_unit()->get_absolute_path()
2161 == tu.get_absolute_path())))
2162 && !ctxt.type_is_emitted(t))
2163 return true;
2164 return false;
2165 }
2166
2167 /// Emit the types that were referenced by other emitted types.
2168 ///
2169 /// This is a sub-routine of write_translation_unit.
2170 ///
2171 /// @param ctxt the write context to use.
2172 ///
2173 /// @param tu the current translation unit that is being emitted.
2174 ///
2175 /// @param indent the indentation string.
2176 ///
2177 /// @param is_last whether @p tu is the last translation unit or not.
2178 static void
write_referenced_types(write_context & ctxt,const translation_unit & tu,const unsigned indent,bool is_last)2179 write_referenced_types(write_context & ctxt,
2180 const translation_unit& tu,
2181 const unsigned indent,
2182 bool is_last)
2183 {
2184 const config& c = ctxt.get_config();
2185 // Now let's handle types that were referenced, but not yet
2186 // emitted because they are either:
2187 // 1/ Types without canonical type
2188 // 2/ or function types (these might have no scope).
2189
2190 while (true)
2191 {
2192 // This set will contain the referenced types we need to emit.
2193 type_ptr_set_type referenced_types_to_emit;
2194
2195 // For each referenced type, ensure that it is either emitted in the
2196 // translation unit to which it belongs or in the last translation
2197 // unit as a last resort.
2198 for (type_ptr_set_type::const_iterator i =
2199 ctxt.get_referenced_types().begin();
2200 i != ctxt.get_referenced_types().end();
2201 ++i)
2202 if (referenced_type_should_be_emitted(*i, ctxt, tu, is_last))
2203 referenced_types_to_emit.insert(*i);
2204
2205 for (fn_type_ptr_set_type::const_iterator i =
2206 ctxt.get_referenced_function_types().begin();
2207 i != ctxt.get_referenced_function_types().end();
2208 ++i)
2209 if (referenced_type_should_be_emitted(*i, ctxt, tu, is_last))
2210 referenced_types_to_emit.insert(*i);
2211
2212 for (type_ptr_set_type::const_iterator i =
2213 ctxt.get_referenced_non_canonical_types().begin();
2214 i != ctxt.get_referenced_non_canonical_types().end();
2215 ++i)
2216 if (referenced_type_should_be_emitted(*i, ctxt, tu, is_last))
2217 referenced_types_to_emit.insert(*i);
2218
2219 if (referenced_types_to_emit.empty())
2220 break;
2221 // Ok, now let's emit the referenced type for good.
2222
2223 // But first, we need to sort them, otherwise, emitting the ABI
2224 // (in xml) of the same binary twice will yield different
2225 // results, because we'd be walking an *unordered* hash table.
2226 std::vector<type_base*> sorted_types =
2227 ctxt.sort_types(referenced_types_to_emit);
2228
2229 // Now, emit the referenced decls in a sorted order.
2230 for (type_base* t : sorted_types)
2231 // We handle types which have declarations *and* function
2232 // types here.
2233 if (ctxt.type_is_emitted(t))
2234 continue;
2235 else if (decl_base* d = get_type_declaration(t))
2236 write_decl_in_scope(decl_base_sptr(d, noop_deleter()), ctxt,
2237 indent + c.get_xml_element_indent());
2238 else if (function_type* f = is_function_type(t))
2239 write_function_type(function_type_sptr(f, noop_deleter()), ctxt,
2240 indent + c.get_xml_element_indent());
2241 else
2242 ABG_ASSERT_NOT_REACHED;
2243
2244 // While emitting those referenced type, other types
2245 // might have been referenced by those referenced types
2246 // themselves! So let's go around again.
2247 }
2248 }
2249
2250 /// Serialize a translation unit to an output stream.
2251 ///
2252 /// @param ctxt the context of the serialization. It contains e.g,
2253 /// the output stream to serialize to.
2254 ///
2255 /// @param tu the translation unit to serialize.
2256 ///
2257 /// @param indent how many indentation spaces to use during the
2258 /// serialization.
2259 ///
2260 /// @param is_last If true, it means the TU to emit is the last one of
2261 /// the corpus. If this is the case, all the remaining referenced
2262 /// types that were not emitted are going to be emitted here,
2263 /// irrespective of if they belong to this TU or not. This is quite a
2264 /// hack. Ideally, we should have a pass that walks all the TUs,
2265 /// detect their non-emitted referenced types, before hand. Then,
2266 /// when we start emitting the TUs, we know for each TU which
2267 /// non-emitted referenced type should be emitted. As we don't yet
2268 /// have such a pass, we do our best for now.
2269 ///
2270 /// @return true upon successful completion, false otherwise.
2271 bool
write_translation_unit(write_context & ctxt,const translation_unit & tu,const unsigned indent,bool is_last)2272 write_translation_unit(write_context& ctxt,
2273 const translation_unit& tu,
2274 const unsigned indent,
2275 bool is_last)
2276 {
2277 if (tu.is_empty() && !is_last)
2278 return false;
2279
2280 if (is_last
2281 && tu.is_empty()
2282 && ctxt.has_non_emitted_referenced_types())
2283 return false;
2284
2285 ostream& o = ctxt.get_ostream();
2286 const config& c = ctxt.get_config();
2287
2288 do_indent(o, indent);
2289
2290 o << "<abi-instr";
2291
2292 if (tu.get_address_size() != 0)
2293 o << " address-size='" << static_cast<int>(tu.get_address_size()) << "'";
2294
2295 std::string tu_path = tu.get_path();
2296 if (ctxt.get_short_locs())
2297 tools_utils::base_name(tu_path, tu_path);
2298 if (!tu_path.empty())
2299 o << " path='" << xml::escape_xml_string(tu_path) << "'";
2300
2301 if (!tu.get_compilation_dir_path().empty() && ctxt.get_write_comp_dir())
2302 o << " comp-dir-path='"
2303 << xml::escape_xml_string(tu.get_compilation_dir_path()) << "'";
2304
2305 if (tu.get_language() != translation_unit::LANG_UNKNOWN)
2306 o << " language='"
2307 << translation_unit_language_to_string(tu.get_language())
2308 <<"'";
2309
2310 if (tu.is_empty() && !is_last)
2311 {
2312 o << "/>\n";
2313 return true;
2314 }
2315
2316 o << ">\n";
2317
2318 write_canonical_types_of_scope(*tu.get_global_scope(),
2319 ctxt, indent + c.get_xml_element_indent());
2320
2321 typedef scope_decl::declarations declarations;
2322 const declarations& decls = tu.get_global_scope()->get_sorted_member_decls();
2323
2324 for (const decl_base_sptr& decl : decls)
2325 {
2326 if (type_base_sptr t = is_type(decl))
2327 {
2328 // Emit declaration-only classes that are needed. Some of
2329 // these classes can be empty. Those beasts can be classes
2330 // that only contain member types. They can also be classes
2331 // considered "opaque".
2332 if (class_decl_sptr class_type = is_class_type(t))
2333 if (class_type->get_is_declaration_only()
2334 && !ctxt.type_is_emitted(class_type))
2335 write_type(class_type, ctxt,
2336 indent + c.get_xml_element_indent());
2337 }
2338 else
2339 {
2340 if (!ctxt.decl_is_emitted(decl))
2341 write_decl(decl, ctxt, indent + c.get_xml_element_indent());
2342 }
2343 }
2344
2345 write_referenced_types(ctxt, tu, indent, is_last);
2346
2347 // Now handle all function types that were not only referenced by
2348 // emitted types.
2349 std::vector<type_base_sptr> sorted_types =
2350 ctxt.sort_types(tu.get_live_fn_types());
2351
2352 for (const type_base_sptr& t : sorted_types)
2353 {
2354 function_type_sptr fn_type = is_function_type(t);
2355
2356 if (fn_type->get_is_artificial() || ctxt.type_is_emitted(fn_type))
2357 // This function type is either already emitted or it's
2358 // artificial (i.e, artificially created just to represent the
2359 // conceptual type of a function), so skip it.
2360 continue;
2361
2362 ABG_ASSERT(fn_type);
2363 write_function_type(fn_type, ctxt, indent + c.get_xml_element_indent());
2364 }
2365
2366 // After we've written out the live function types, we need to write
2367 // the types they referenced.
2368 write_referenced_types(ctxt, tu, indent, is_last);
2369
2370 do_indent(o, indent);
2371 o << "</abi-instr>\n";
2372
2373 return true;
2374 }
2375
2376 /// Serialize a pointer to an instance of basic type declaration, into
2377 /// an output stream.
2378 ///
2379 /// @param d the basic type declaration to serialize.
2380 ///
2381 /// @param ctxt the context of the serialization. It contains e.g, the
2382 /// output stream to serialize to.
2383 ///
2384 /// @param indent how many indentation spaces to use during the
2385 /// serialization.
2386 ///
2387 /// @return true upon successful completion, false otherwise.
2388 static bool
write_type_decl(const type_decl_sptr & d,write_context & ctxt,unsigned indent)2389 write_type_decl(const type_decl_sptr& d, write_context& ctxt, unsigned indent)
2390 {
2391 if (!d)
2392 return false;
2393
2394 ostream& o = ctxt.get_ostream();
2395
2396 annotate(d, ctxt, indent);
2397
2398 do_indent(o, indent);
2399
2400 o << "<type-decl name='" << xml::escape_xml_string(d->get_name()) << "'";
2401
2402 write_is_anonymous(d, o);
2403
2404 write_size_and_alignment(d, o);
2405
2406 write_is_declaration_only(d, o);
2407
2408 write_location(d, ctxt);
2409
2410 o << " id='" << ctxt.get_id_for_type(d) << "'" << "/>\n";
2411
2412 ctxt.record_type_as_emitted(d);
2413
2414 return true;
2415 }
2416
2417 /// Serialize a namespace declaration int an output stream.
2418 ///
2419 /// @param decl the namespace declaration to serialize.
2420 ///
2421 /// @param ctxt the context of the serialization. It contains e.g, the
2422 /// output stream to serialize to.
2423 ///
2424 /// @param indent how many indentation spaces to use during the
2425 /// serialization.
2426 ///
2427 /// @return true upon successful completion, false otherwise.
2428 static bool
write_namespace_decl(const namespace_decl_sptr & decl,write_context & ctxt,unsigned indent)2429 write_namespace_decl(const namespace_decl_sptr& decl,
2430 write_context& ctxt, unsigned indent)
2431 {
2432 if (!decl || decl->is_empty_or_has_empty_sub_namespaces())
2433 return false;
2434
2435 ostream& o = ctxt.get_ostream();
2436 const config &c = ctxt.get_config();
2437
2438 annotate(decl, ctxt, indent);
2439
2440 do_indent(o, indent);
2441
2442 o << "<namespace-decl name='"
2443 << xml::escape_xml_string(decl->get_name())
2444 << "'>\n";
2445
2446 typedef scope_decl::declarations declarations;
2447 typedef declarations::const_iterator const_iterator;
2448 const declarations& d = decl->get_sorted_member_decls();
2449
2450 write_canonical_types_of_scope(*decl, ctxt,
2451 indent + c.get_xml_element_indent());
2452
2453 for (const_iterator i = d.begin(); i != d.end(); ++i)
2454 {
2455 if (type_base_sptr t = is_type(*i))
2456 if (ctxt.type_is_emitted(t))
2457 // This type has already been emitted to the current
2458 // translation unit so do not emit it again.
2459 continue;
2460 write_decl(*i, ctxt, indent + c.get_xml_element_indent());
2461 }
2462
2463 do_indent(o, indent);
2464 o << "</namespace-decl>\n";
2465
2466 return true;
2467 }
2468
2469 /// Serialize a qualified type declaration to an output stream.
2470 ///
2471 /// @param decl the qualfied type declaration to write.
2472 ///
2473 /// @param ctxt the write context.
2474 ///
2475 /// @param indent the number of space to indent to during the
2476 /// serialization.
2477 ///
2478 /// @return true upon successful completion, false otherwise.
2479 static bool
write_qualified_type_def(const qualified_type_def_sptr & decl,write_context & ctxt,unsigned indent)2480 write_qualified_type_def(const qualified_type_def_sptr& decl,
2481 write_context& ctxt,
2482 unsigned indent)
2483 {
2484 if (!decl)
2485 return false;
2486
2487 ostream& o = ctxt.get_ostream();
2488
2489
2490 type_base_sptr underlying_type = decl->get_underlying_type();
2491
2492 annotate(decl, ctxt, indent);
2493
2494 do_indent(o, indent);
2495 o << "<qualified-type-def type-id='"
2496 << ctxt.get_id_for_type(underlying_type)
2497 << "'";
2498
2499 ctxt.record_type_as_referenced(underlying_type);
2500
2501 if (decl->get_cv_quals() & qualified_type_def::CV_CONST)
2502 o << " const='yes'";
2503 if (decl->get_cv_quals() & qualified_type_def::CV_VOLATILE)
2504 o << " volatile='yes'";
2505 if (decl->get_cv_quals() & qualified_type_def::CV_RESTRICT)
2506 o << " restrict='yes'";
2507
2508 write_location(static_pointer_cast<decl_base>(decl), ctxt);
2509
2510 o << " id='" << ctxt.get_id_for_type(decl) << "'/>\n";
2511
2512 ctxt.record_type_as_emitted(decl);
2513
2514 return true;
2515 }
2516
2517 /// Serialize a pointer to an instance of pointer_type_def.
2518 ///
2519 /// @param decl the pointer_type_def to serialize.
2520 ///
2521 /// @param id the type id identitifier to use in the serialized
2522 /// output. If this is empty, the function will compute an
2523 /// appropriate one. This is useful when this function is called to
2524 /// serialize the underlying type of a member type; in that case, the
2525 /// caller has already computed the id of the *member type*, and that
2526 /// id is the one to be written as the value of the 'id' attribute of
2527 /// the XML element of the underlying type.
2528 ///
2529 /// @param ctxt the context of the serialization.
2530 ///
2531 /// @param indent the number of indentation white spaces to use.
2532 ///
2533 /// @return true upon successful completion, false otherwise.
2534 static bool
write_pointer_type_def(const pointer_type_def_sptr & decl,write_context & ctxt,unsigned indent)2535 write_pointer_type_def(const pointer_type_def_sptr& decl,
2536 write_context& ctxt,
2537 unsigned indent)
2538 {
2539 if (!decl)
2540 return false;
2541
2542 ostream& o = ctxt.get_ostream();
2543
2544
2545 type_base_sptr pointed_to_type = decl->get_pointed_to_type();
2546
2547 annotate(decl->get_canonical_type(), ctxt, indent);
2548
2549 do_indent(o, indent);
2550 o << "<pointer-type-def type-id='"
2551 << ctxt.get_id_for_type(pointed_to_type)
2552 << "'";
2553
2554 ctxt.record_type_as_referenced(pointed_to_type);
2555
2556 write_size_and_alignment(decl, o,
2557 (ctxt.get_write_default_sizes()
2558 ? 0
2559 : decl->get_translation_unit()->get_address_size()),
2560 0);
2561
2562 string id = ctxt.get_id_for_type(decl);
2563 o << " id='" << id << "'";
2564
2565 write_location(static_pointer_cast<decl_base>(decl), ctxt);
2566 o << "/>\n";
2567
2568 ctxt.record_type_as_emitted(decl);
2569
2570 return true;
2571 }
2572
2573 /// Serialize a pointer to an instance of reference_type_def.
2574 ///
2575 /// @param decl the reference_type_def to serialize.
2576 ///
2577 /// @param ctxt the context of the serialization.
2578 ///
2579 /// @param indent the number of indentation white spaces to use.
2580 ///
2581 /// @return true upon successful completion, false otherwise.
2582 static bool
write_reference_type_def(const reference_type_def_sptr & decl,write_context & ctxt,unsigned indent)2583 write_reference_type_def(const reference_type_def_sptr& decl,
2584 write_context& ctxt,
2585 unsigned indent)
2586 {
2587 if (!decl)
2588 return false;
2589
2590 annotate(decl->get_canonical_type(), ctxt, indent);
2591
2592 ostream& o = ctxt.get_ostream();
2593
2594 do_indent(o, indent);
2595
2596 o << "<reference-type-def kind='";
2597 if (decl->is_lvalue())
2598 o << "lvalue";
2599 else
2600 o << "rvalue";
2601 o << "'";
2602
2603 type_base_sptr pointed_to_type = decl->get_pointed_to_type();
2604 o << " type-id='" << ctxt.get_id_for_type(pointed_to_type) << "'";
2605
2606 ctxt.record_type_as_referenced(pointed_to_type);
2607
2608 if (function_type_sptr f = is_function_type(decl->get_pointed_to_type()))
2609 ctxt.record_type_as_referenced(f);
2610
2611 write_size_and_alignment(decl, o,
2612 (ctxt.get_write_default_sizes()
2613 ? 0
2614 : decl->get_translation_unit()->get_address_size()),
2615 0);
2616
2617 o << " id='" << ctxt.get_id_for_type(decl) << "'";
2618
2619 write_location(static_pointer_cast<decl_base>(decl), ctxt);
2620
2621 o << "/>\n";
2622
2623 ctxt.record_type_as_emitted(decl);
2624
2625 return true;
2626 }
2627
2628 /// Serialize an instance of @ref array_type_def::subrange_type.
2629 ///
2630 /// @param decl the array_type_def::subrange_type to serialize.
2631 ///
2632 /// @param ctxt the context of the serialization.
2633 ///
2634 /// @param indent the number of indentation white spaces to use.
2635 ///
2636 /// return true upon successful completion, false otherwise.
2637 static bool
write_array_subrange_type(const array_type_def::subrange_sptr & decl,write_context & ctxt,unsigned indent)2638 write_array_subrange_type(const array_type_def::subrange_sptr& decl,
2639 write_context& ctxt,
2640 unsigned indent)
2641 {
2642 if (!decl)
2643 return false;
2644
2645 annotate(decl, ctxt, indent);
2646
2647 ostream& o = ctxt.get_ostream();
2648
2649 do_indent(o, indent);
2650
2651 o << "<subrange";
2652
2653 if (!decl->get_name().empty())
2654 o << " name='" << decl->get_name() << "'";
2655
2656 o << " length='";
2657 if (decl->is_infinite())
2658 o << "infinite";
2659 else
2660 o << decl->get_length();
2661
2662 o << "'";
2663
2664 if (decl->get_lower_bound())
2665 {
2666 ABG_ASSERT(decl->is_infinite()
2667 || (decl->get_length() ==
2668 (uint64_t) (decl->get_upper_bound()
2669 - decl->get_lower_bound() + 1)));
2670 o << " lower-bound='" << decl->get_lower_bound() << "' upper-bound='"
2671 << decl->get_upper_bound() << "'";
2672 }
2673
2674 type_base_sptr underlying_type = decl->get_underlying_type();
2675 if (underlying_type)
2676 {
2677 o << " type-id='"
2678 << ctxt.get_id_for_type(underlying_type)
2679 << "'";
2680 ctxt.record_type_as_referenced(underlying_type);
2681 }
2682
2683 o << " id='" << ctxt.get_id_for_type(decl) << "'";
2684
2685 write_location(decl->get_location(), ctxt);
2686
2687 o << "/>\n";
2688
2689 ctxt.record_type_as_emitted(decl);
2690
2691 return true;
2692 }
2693
2694 /// Serialize a pointer to an instance of array_type_def.
2695 ///
2696 /// @param decl the array_type_def to serialize.
2697 ///
2698 /// @param ctxt the context of the serialization.
2699 ///
2700 /// @param indent the number of indentation white spaces to use.
2701 ///
2702 /// @return true upon successful completion, false otherwise.
2703 static bool
write_array_type_def(const array_type_def_sptr & decl,write_context & ctxt,unsigned indent)2704 write_array_type_def(const array_type_def_sptr& decl,
2705 write_context& ctxt,
2706 unsigned indent)
2707 {
2708 if (!decl)
2709 return false;
2710
2711 annotate(decl, ctxt, indent);
2712
2713 ostream& o = ctxt.get_ostream();
2714
2715 do_indent(o, indent);
2716 o << "<array-type-def";
2717
2718 o << " dimensions='" << decl->get_dimension_count() << "'";
2719
2720 type_base_sptr element_type = decl->get_element_type();
2721 o << " type-id='" << ctxt.get_id_for_type(element_type) << "'";
2722
2723 ctxt.record_type_as_referenced(element_type);
2724
2725 write_array_size_and_alignment(decl, o);
2726
2727 o << " id='" << ctxt.get_id_for_type(decl) << "'";
2728
2729 write_location(static_pointer_cast<decl_base>(decl), ctxt);
2730
2731 if (!decl->get_dimension_count())
2732 o << "/>\n";
2733 else
2734 {
2735 o << ">\n";
2736
2737 vector<array_type_def::subrange_sptr>::const_iterator si;
2738
2739 for (si = decl->get_subranges().begin();
2740 si != decl->get_subranges().end(); ++si)
2741 {
2742 unsigned local_indent =
2743 indent + ctxt.get_config().get_xml_element_indent();
2744 write_array_subrange_type(*si, ctxt, local_indent);
2745 }
2746
2747 do_indent(o, indent);
2748 o << "</array-type-def>\n";
2749 }
2750
2751 ctxt.record_type_as_emitted(decl);
2752
2753 return true;
2754 }
2755
2756 /// Serialize a pointer to an instance of enum_type_decl.
2757 ///
2758 /// @param decl the enum_type_decl to serialize.
2759 ///
2760 /// @param ctxt the context of the serialization.
2761 ///
2762 /// @param indent the number of indentation white spaces to use.
2763 ///
2764 /// @return true upon successful completion, false otherwise.
2765 static bool
write_enum_type_decl(const enum_type_decl_sptr & d,write_context & ctxt,unsigned indent)2766 write_enum_type_decl(const enum_type_decl_sptr& d,
2767 write_context& ctxt,
2768 unsigned indent)
2769 {
2770 if (!d)
2771 return false;
2772
2773 enum_type_decl_sptr decl = is_enum_type(look_through_decl_only_enum(d));
2774
2775 annotate(decl->get_canonical_type(), ctxt, indent);
2776
2777 ostream& o = ctxt.get_ostream();
2778
2779 do_indent(o, indent);
2780 o << "<enum-decl name='" << xml::escape_xml_string(decl->get_name()) << "'";
2781
2782 write_is_anonymous(decl, o);
2783 write_naming_typedef(decl, ctxt);
2784 write_is_artificial(decl, o);
2785 write_is_non_reachable(is_type(decl), o);
2786
2787 if (!decl->get_linkage_name().empty())
2788 o << " linkage-name='"
2789 << xml::escape_xml_string(decl->get_linkage_name())
2790 << "'";
2791
2792 write_location(decl, ctxt);
2793 write_is_declaration_only(decl, o);
2794
2795 o << " id='" << ctxt.get_id_for_type(decl) << "'>\n";
2796
2797 do_indent(o, indent + ctxt.get_config().get_xml_element_indent());
2798 o << "<underlying-type type-id='"
2799 << ctxt.get_id_for_type(decl->get_underlying_type())
2800 << "'/>\n";
2801
2802 for (enum_type_decl::enumerators::const_iterator i =
2803 decl->get_enumerators().begin();
2804 i != decl->get_enumerators().end();
2805 ++i)
2806 {
2807 do_indent(o, indent + ctxt.get_config().get_xml_element_indent());
2808 o << "<enumerator name='"
2809 << i->get_name()
2810 << "' value='"
2811 << i->get_value()
2812 << "'/>\n";
2813 }
2814
2815 do_indent(o, indent);
2816 o << "</enum-decl>\n";
2817
2818 ctxt.record_type_as_emitted(decl);
2819
2820 return true;
2821 }
2822
2823 /// Serialize an @ref elf_symbol to an XML element of name
2824 /// 'elf-symbol'.
2825 ///
2826 /// @param sym the elf symbol to serialize.
2827 ///
2828 /// @param ctxt the read context to use.
2829 ///
2830 /// @param indent the number of white spaces to use as indentation.
2831 ///
2832 /// @return true iff the function completed successfully.
2833 static bool
write_elf_symbol(const elf_symbol_sptr & sym,write_context & ctxt,unsigned indent)2834 write_elf_symbol(const elf_symbol_sptr& sym,
2835 write_context& ctxt,
2836 unsigned indent)
2837 {
2838 if (!sym)
2839 return false;
2840
2841 ostream &o = ctxt.get_ostream();
2842
2843 annotate(sym, ctxt, indent);
2844 do_indent(o, indent);
2845 o << "<elf-symbol name='" << sym->get_name() << "'";
2846 if (sym->is_variable() && sym->get_size())
2847 o << " size='" << sym->get_size() << "'";
2848
2849 if (!sym->get_version().is_empty())
2850 {
2851 o << " version='" << sym->get_version().str() << "'";
2852 o << " is-default-version='";
2853 if (sym->get_version().is_default())
2854 o << "yes";
2855 else
2856 o << "no";
2857 o << "'";
2858 }
2859
2860 write_elf_symbol_type(sym->get_type(), o);
2861
2862 write_elf_symbol_binding(sym->get_binding(), o);
2863
2864 write_elf_symbol_visibility(sym->get_visibility(), o);
2865
2866 write_elf_symbol_aliases(*sym, o);
2867
2868 o << " is-defined='";
2869 if (sym->is_defined())
2870 o << "yes";
2871 else
2872 o << "no";
2873 o << "'";
2874
2875 if (sym->is_common_symbol())
2876 o << " is-common='yes'";
2877
2878 if (sym->get_crc().has_value())
2879 o << " crc='"
2880 << std::hex << std::showbase << sym->get_crc().value()
2881 << std::dec << std::noshowbase << "'";
2882
2883 if (sym->get_namespace().has_value())
2884 o << " namespace='" << sym->get_namespace().value() << "'";
2885
2886 o << "/>\n";
2887
2888 return true;
2889 }
2890
2891 /// Write the elf symbol database to the output associated to the
2892 /// current context.
2893 ///
2894 /// @param syms the sorted elf symbol data to write out.
2895 ///
2896 /// @param ctxt the context to consider.
2897 ///
2898 /// @param indent the number of white spaces to use as indentation.
2899 ///
2900 /// @return true upon successful completion.
2901 static bool
write_elf_symbols_table(const elf_symbols & syms,write_context & ctxt,unsigned indent)2902 write_elf_symbols_table(const elf_symbols& syms,
2903 write_context& ctxt,
2904 unsigned indent)
2905 {
2906 if (syms.empty())
2907 return false;
2908
2909 for (elf_symbols::const_iterator it = syms.begin(); it != syms.end(); ++it)
2910 write_elf_symbol(*it, ctxt, indent);
2911
2912 return true;
2913 }
2914
2915 /// Write a vector of dependency names for the current corpus we are
2916 /// writting.
2917 ///
2918 /// @param needed the vector of dependency names to write.
2919 ///
2920 /// @param ctxt the write context to use for the writting.
2921 ///
2922 /// @param indent the number of indendation spaces to use.
2923 ///
2924 /// @return true upon successful completion, false otherwise.
2925 static bool
write_elf_needed(const vector<string> & needed,write_context & ctxt,unsigned indent)2926 write_elf_needed(const vector<string>& needed,
2927 write_context& ctxt,
2928 unsigned indent)
2929 {
2930 if (needed.empty())
2931 return false;
2932
2933 ostream& o = ctxt.get_ostream();
2934
2935 for (vector<string>::const_iterator i = needed.begin();
2936 i != needed.end();
2937 ++i)
2938 {
2939 do_indent(o, indent);
2940 o << "<dependency name='" << *i << "'/>\n";
2941 }
2942 return true;
2943 }
2944
2945 /// Serialize a pointer to an instance of typedef_decl.
2946 ///
2947 /// @param decl the typedef_decl to serialize.
2948 ///
2949 /// @param ctxt the context of the serialization.
2950 ///
2951 /// @param indent the number of indentation white spaces to use.
2952 ///
2953 /// @return true upon successful completion, false otherwise.
2954 static bool
write_typedef_decl(const typedef_decl_sptr & decl,write_context & ctxt,unsigned indent)2955 write_typedef_decl(const typedef_decl_sptr& decl,
2956 write_context& ctxt,
2957 unsigned indent)
2958 {
2959 if (!decl)
2960 return false;
2961
2962 ostream &o = ctxt.get_ostream();
2963
2964 annotate(decl, ctxt, indent);
2965
2966 do_indent(o, indent);
2967
2968 o << "<typedef-decl name='"
2969 << xml::escape_xml_string(decl->get_name())
2970 << "'";
2971
2972 type_base_sptr underlying_type = decl->get_underlying_type();
2973 o << " type-id='" << ctxt.get_id_for_type(underlying_type) << "'";
2974 ctxt.record_type_as_referenced(underlying_type);
2975
2976 write_location(decl, ctxt);
2977
2978 o << " id='" << ctxt.get_id_for_type(decl) << "'/>\n";
2979
2980 ctxt.record_type_as_emitted(decl);
2981
2982 return true;
2983 }
2984
2985 /// Serialize a pointer to an instances of var_decl.
2986 ///
2987 /// @param decl the var_decl to serialize.
2988 ///
2989 /// @param ctxt the context of the serialization.
2990 ///
2991 /// @param write_linkage_name if true, serialize the mangled name of
2992 /// this variable.
2993 ///
2994 /// @param indent the number of indentation white spaces to use.
2995 ///
2996 /// @return true upon successful completion, false otherwise.
2997 static bool
write_var_decl(const var_decl_sptr & decl,write_context & ctxt,bool write_linkage_name,unsigned indent)2998 write_var_decl(const var_decl_sptr& decl, write_context& ctxt,
2999 bool write_linkage_name, unsigned indent)
3000 {
3001 if (!decl)
3002 return false;
3003
3004 annotate(decl, ctxt, indent);
3005
3006 ostream &o = ctxt.get_ostream();
3007
3008 do_indent(o, indent);
3009
3010 o << "<var-decl name='" << xml::escape_xml_string(decl->get_name()) << "'";
3011 type_base_sptr var_type = decl->get_type();
3012 o << " type-id='" << ctxt.get_id_for_type(var_type) << "'";
3013 ctxt.record_type_as_referenced(var_type);
3014
3015 if (write_linkage_name)
3016 {
3017 const string& linkage_name = decl->get_linkage_name();
3018 if (!linkage_name.empty())
3019 o << " mangled-name='" << linkage_name << "'";
3020 }
3021
3022 write_visibility(decl, o);
3023
3024 write_binding(decl, o);
3025
3026 write_location(decl, ctxt);
3027
3028 write_elf_symbol_reference(decl->get_symbol(), o);
3029
3030 o << "/>\n";
3031
3032 ctxt.record_decl_as_emitted(decl);
3033
3034 return true;
3035 }
3036
3037 /// Serialize a pointer to a function_decl.
3038 ///
3039 /// @param decl the pointer to function_decl to serialize.
3040 ///
3041 /// @param ctxt the context of the serialization.
3042 ///
3043 /// @param skip_first_parm if true, do not serialize the first
3044 /// parameter of the function decl.
3045 ///
3046 /// @param indent the number of indentation white spaces to use.
3047 ///
3048 /// @return true upon successful completion, false otherwise.
3049 static bool
write_function_decl(const function_decl_sptr & decl,write_context & ctxt,bool skip_first_parm,unsigned indent)3050 write_function_decl(const function_decl_sptr& decl, write_context& ctxt,
3051 bool skip_first_parm, unsigned indent)
3052 {
3053 if (!decl)
3054 return false;
3055
3056 annotate(decl, ctxt, indent);
3057
3058 ostream &o = ctxt.get_ostream();
3059
3060 do_indent(o, indent);
3061
3062 o << "<function-decl name='"
3063 << xml::escape_xml_string(decl->get_name())
3064 << "'";
3065
3066 if (!decl->get_linkage_name().empty())
3067 o << " mangled-name='"
3068 << xml::escape_xml_string(decl->get_linkage_name()) << "'";
3069
3070 write_location(decl, ctxt);
3071
3072 if (decl->is_declared_inline())
3073 o << " declared-inline='yes'";
3074
3075 write_visibility(decl, o);
3076
3077 write_binding(decl, o);
3078
3079 write_size_and_alignment(decl->get_type(), o,
3080 (ctxt.get_write_default_sizes()
3081 ? 0
3082 : decl->get_translation_unit()->get_address_size()),
3083 0);
3084 write_elf_symbol_reference(decl->get_symbol(), o);
3085
3086 o << ">\n";
3087
3088 type_base_sptr parm_type;
3089 vector<shared_ptr<function_decl::parameter> >::const_iterator pi =
3090 decl->get_parameters().begin();
3091 for ((skip_first_parm && pi != decl->get_parameters().end()) ? ++pi: pi;
3092 pi != decl->get_parameters().end();
3093 ++pi)
3094 {
3095 if ((*pi)->get_variadic_marker())
3096 {
3097 do_indent(o, indent + ctxt.get_config().get_xml_element_indent());
3098 o << "<parameter is-variadic='yes'";
3099 }
3100 else
3101 {
3102 parm_type = (*pi)->get_type();
3103
3104 annotate(*pi, ctxt,
3105 indent + ctxt.get_config().get_xml_element_indent());
3106
3107 do_indent(o, indent + ctxt.get_config().get_xml_element_indent());
3108
3109 o << "<parameter type-id='"
3110 << ctxt.get_id_for_type(parm_type)
3111 << "'";
3112 ctxt.record_type_as_referenced(parm_type);
3113
3114 if (ctxt.get_write_parameter_names() && !(*pi)->get_name().empty())
3115 o << " name='" << (*pi)->get_name() << "'";
3116 }
3117 write_is_artificial(*pi, o);
3118 write_location((*pi)->get_location(), ctxt);
3119 o << "/>\n";
3120 }
3121
3122 if (shared_ptr<type_base> return_type = decl->get_return_type())
3123 {
3124 annotate(return_type , ctxt,
3125 indent + ctxt.get_config().get_xml_element_indent());
3126 do_indent(o, indent + ctxt.get_config().get_xml_element_indent());
3127 o << "<return type-id='" << ctxt.get_id_for_type(return_type) << "'/>\n";
3128 ctxt.record_type_as_referenced(return_type);
3129 }
3130
3131 do_indent(o, indent);
3132 o << "</function-decl>\n";
3133
3134 ctxt.record_decl_as_emitted(decl);
3135
3136 return true;
3137 }
3138
3139 /// Serialize a function_type.
3140 ///
3141 /// @param decl the pointer to function_type to serialize.
3142 ///
3143 /// @param ctxt the context of the serialization.
3144 ///
3145 /// @param indent the number of indentation white spaces to use.
3146 ///
3147 /// @return true upon successful completion, false otherwise.
3148 static bool
write_function_type(const function_type_sptr & fn_type,write_context & ctxt,unsigned indent)3149 write_function_type(const function_type_sptr& fn_type,
3150 write_context& ctxt, unsigned indent)
3151 {
3152 if (!fn_type)
3153 return false;
3154
3155 ostream &o = ctxt.get_ostream();
3156
3157 annotate(fn_type, ctxt, indent);
3158
3159 do_indent(o, indent);
3160
3161 o << "<function-type";
3162
3163 write_size_and_alignment(fn_type, o,
3164 (ctxt.get_write_default_sizes()
3165 ? 0
3166 : fn_type->get_translation_unit()->get_address_size()),
3167 0);
3168
3169 if (method_type_sptr method_type = is_method_type(fn_type))
3170 {
3171 o << " method-class-id='"
3172 << ctxt.get_id_for_type(method_type->get_class_type())
3173 << "'";
3174
3175 write_cdtor_const_static(/*is_ctor=*/false, /*is_dtor=*/false,
3176 /*is_const=*/method_type->get_is_const(),
3177 /*is_static=*/false, o);
3178 }
3179
3180 o << " id='" << ctxt.get_id_for_type(fn_type) << "'" << ">\n";
3181
3182 type_base_sptr parm_type;
3183 for (vector<function_decl::parameter_sptr>::const_iterator pi =
3184 fn_type->get_parameters().begin();
3185 pi != fn_type->get_parameters().end();
3186 ++pi)
3187 {
3188
3189 if ((*pi)->get_variadic_marker())
3190 {
3191 do_indent(o, indent + ctxt.get_config().get_xml_element_indent());
3192 o << "<parameter is-variadic='yes'";
3193 }
3194 else
3195 {
3196 parm_type = (*pi)->get_type();
3197
3198 annotate(*pi, ctxt, indent + ctxt.get_config().get_xml_element_indent());
3199
3200 do_indent(o, indent + ctxt.get_config().get_xml_element_indent());
3201 o << "<parameter type-id='"
3202 << ctxt.get_id_for_type(parm_type)
3203 << "'";
3204 ctxt.record_type_as_referenced(parm_type);
3205
3206 if (!(*pi)->get_name().empty())
3207 {
3208 string name = xml::escape_xml_string((*pi)->get_name());
3209 o << " name='" << name << "'";
3210 }
3211 }
3212 write_is_artificial(*pi, o);
3213 o << "/>\n";
3214 }
3215
3216 if (type_base_sptr return_type = fn_type->get_return_type())
3217 {
3218 annotate(return_type, ctxt, indent + ctxt.get_config().get_xml_element_indent());
3219 do_indent(o, indent + ctxt.get_config().get_xml_element_indent());
3220 o << "<return type-id='" << ctxt.get_id_for_type(return_type) << "'/>\n";
3221 ctxt.record_type_as_referenced(return_type);
3222 }
3223
3224 do_indent(o, indent);
3225 o << "</function-type>\n";
3226
3227 ctxt.record_type_as_emitted(fn_type);
3228 return true;
3229 }
3230
3231 /// Write the opening tag of a 'class-decl' element.
3232 ///
3233 /// @param decl the class declaration to serialize.
3234 ///
3235 /// @param ctxt the write context to use.
3236 ///
3237 /// @param indent the number of white space to use for indentation.
3238 ///
3239 /// @param prepare_to_handle_members if set to true, then this function
3240 /// figures out if the opening tag should be for an empty element or
3241 /// not. If set to false, then the opening tag is unconditionnaly for
3242 /// a non-empty element.
3243 ///
3244 /// @return true upon successful completion.
3245 static bool
write_class_decl_opening_tag(const class_decl_sptr & decl,write_context & ctxt,unsigned indent,bool prepare_to_handle_members)3246 write_class_decl_opening_tag(const class_decl_sptr& decl,
3247 write_context& ctxt,
3248 unsigned indent,
3249 bool prepare_to_handle_members)
3250 {
3251 if (!decl)
3252 return false;
3253
3254 ostream& o = ctxt.get_ostream();
3255
3256 do_indent_to_level(ctxt, indent, 0);
3257
3258 o << "<class-decl name='" << xml::escape_xml_string(decl->get_name()) << "'";
3259
3260 write_size_and_alignment(decl, o);
3261
3262 write_is_struct(decl, o);
3263
3264 write_is_anonymous(decl, o);
3265
3266 write_is_artificial(decl, o);
3267
3268 write_is_non_reachable(is_type(decl), o);
3269
3270 write_naming_typedef(decl, ctxt);
3271
3272 write_visibility(decl, o);
3273
3274 write_location(decl, ctxt);
3275
3276 write_is_declaration_only(decl, o);
3277
3278 if (decl->get_earlier_declaration())
3279 {
3280 // This instance is the definition of an earlier declaration.
3281 o << " def-of-decl-id='"
3282 << ctxt.get_id_for_type(is_type(decl->get_earlier_declaration()))
3283 << "'";
3284 }
3285
3286 o << " id='" << ctxt.get_id_for_type(decl) << "'";
3287
3288 if (prepare_to_handle_members && decl->has_no_base_nor_member())
3289 o << "/>\n";
3290 else
3291 o << ">\n";
3292
3293 return true;
3294 }
3295
3296 /// Write the opening tag of a 'union-decl' element.
3297 ///
3298 /// @param decl the union declaration to serialize.
3299 ///
3300 /// @param ctxt the write context to use.
3301 ///
3302 /// @param indent the number of white space to use for indentation.
3303 ///
3304 /// @param prepare_to_handle_members if set to true, then this function
3305 /// figures out if the opening tag should be for an empty element or
3306 /// not. If set to false, then the opening tag is unconditionnaly for
3307 /// a non-empty element.
3308 ///
3309 /// @return true upon successful completion.
3310 static bool
write_union_decl_opening_tag(const union_decl_sptr & decl,write_context & ctxt,unsigned indent,bool prepare_to_handle_members)3311 write_union_decl_opening_tag(const union_decl_sptr& decl,
3312 write_context& ctxt,
3313 unsigned indent,
3314 bool prepare_to_handle_members)
3315 {
3316 if (!decl)
3317 return false;
3318
3319 ostream& o = ctxt.get_ostream();
3320
3321 do_indent_to_level(ctxt, indent, 0);
3322
3323 o << "<union-decl name='" << xml::escape_xml_string(decl->get_name()) << "'";
3324
3325 if (!decl->get_is_declaration_only())
3326 write_size_and_alignment(decl, o);
3327
3328 write_is_anonymous(decl, o);
3329
3330 write_naming_typedef(decl, ctxt);
3331
3332 write_visibility(decl, o);
3333
3334 write_is_artificial(decl, o);
3335
3336 write_is_non_reachable(is_type(decl), o);
3337
3338 write_location(decl, ctxt);
3339
3340 write_is_declaration_only(decl, o);
3341
3342 o << " id='" << ctxt.get_id_for_type(decl) << "'";
3343
3344 if (prepare_to_handle_members && decl->has_no_member())
3345 o << "/>\n";
3346 else
3347 o << ">\n";
3348
3349 return true;
3350 }
3351
3352 /// Serialize a class_decl type.
3353 ///
3354 /// @param d the pointer to class_decl to serialize.
3355 ///
3356 /// @param ctxt the context of the serialization.
3357 ///
3358 /// @param indent the initial indentation to use.
3359 static bool
write_class_decl(const class_decl_sptr & d,write_context & ctxt,unsigned indent)3360 write_class_decl(const class_decl_sptr& d,
3361 write_context& ctxt,
3362 unsigned indent)
3363 {
3364 if (!d)
3365 return false;
3366
3367 class_decl_sptr decl = is_class_type(look_through_decl_only_class(d));
3368
3369 annotate(decl, ctxt, indent);
3370
3371 ostream& o = ctxt.get_ostream();
3372
3373 write_class_decl_opening_tag(decl, ctxt, indent,
3374 /*prepare_to_handle_members=*/true);
3375
3376 if (!decl->has_no_base_nor_member())
3377 {
3378 unsigned nb_ws = get_indent_to_level(ctxt, indent, 1);
3379 type_base_sptr base_type;
3380 for (class_decl::base_specs::const_iterator base =
3381 decl->get_base_specifiers().begin();
3382 base != decl->get_base_specifiers().end();
3383 ++base)
3384 {
3385 annotate((*base)->get_base_class(), ctxt, nb_ws);
3386 do_indent(o, nb_ws);
3387 o << "<base-class";
3388
3389 write_access((*base)->get_access_specifier(), o);
3390
3391 write_layout_offset (*base, o);
3392
3393 if ((*base)->get_is_virtual ())
3394 o << " is-virtual='yes'";
3395
3396 base_type = (*base)->get_base_class();
3397 o << " type-id='"
3398 << ctxt.get_id_for_type(base_type)
3399 << "'/>\n";
3400
3401 ctxt.record_type_as_referenced(base_type);
3402 }
3403
3404 write_canonical_types_of_scope(*decl, ctxt, nb_ws,
3405 /*is_member_type=*/true);
3406
3407 for (class_decl::member_types::const_iterator ti =
3408 decl->get_member_types().begin();
3409 ti != decl->get_member_types().end();
3410 ++ti)
3411 if (!(*ti)->get_naked_canonical_type())
3412 write_member_type(*ti, ctxt, nb_ws);
3413
3414 for (class_decl::data_members::const_iterator data =
3415 decl->get_data_members().begin();
3416 data != decl->get_data_members().end();
3417 ++data)
3418 {
3419 do_indent(o, nb_ws);
3420 o << "<data-member";
3421 write_access(get_member_access_specifier(*data), o);
3422
3423 bool is_static = get_member_is_static(*data);
3424 write_cdtor_const_static(/*is_ctor=*/false,
3425 /*is_dtor=*/false,
3426 /*is_const=*/false,
3427 /*is_static=*/is_static,
3428 o);
3429 write_layout_offset(*data, o);
3430 o << ">\n";
3431
3432 write_var_decl(*data, ctxt, is_static,
3433 get_indent_to_level(ctxt, indent, 2));
3434
3435 do_indent_to_level(ctxt, indent, 1);
3436 o << "</data-member>\n";
3437 }
3438
3439 for (class_decl::member_functions::const_iterator f =
3440 decl->get_member_functions().begin();
3441 f != decl->get_member_functions().end();
3442 ++f)
3443 {
3444 function_decl_sptr fn = *f;
3445 if (get_member_function_is_virtual(fn))
3446 // All virtual member functions are emitted together,
3447 // later.
3448 continue;
3449
3450 ABG_ASSERT(!get_member_function_is_virtual(fn));
3451
3452 do_indent(o, nb_ws);
3453 o << "<member-function";
3454 write_access(get_member_access_specifier(fn), o);
3455 write_cdtor_const_static( get_member_function_is_ctor(fn),
3456 get_member_function_is_dtor(fn),
3457 get_member_function_is_const(fn),
3458 get_member_is_static(fn),
3459 o);
3460 o << ">\n";
3461
3462 write_function_decl(fn, ctxt,
3463 /*skip_first_parameter=*/false,
3464 get_indent_to_level(ctxt, indent, 2));
3465
3466 do_indent_to_level(ctxt, indent, 1);
3467 o << "</member-function>\n";
3468 }
3469
3470 for (class_decl::member_functions::const_iterator f =
3471 decl->get_virtual_mem_fns().begin();
3472 f != decl->get_virtual_mem_fns().end();
3473 ++f)
3474 {
3475 function_decl_sptr fn = *f;
3476
3477 ABG_ASSERT(get_member_function_is_virtual(fn));
3478
3479 do_indent(o, nb_ws);
3480 o << "<member-function";
3481 write_access(get_member_access_specifier(fn), o);
3482 write_cdtor_const_static( get_member_function_is_ctor(fn),
3483 get_member_function_is_dtor(fn),
3484 get_member_function_is_const(fn),
3485 get_member_is_static(fn),
3486 o);
3487 write_voffset(fn, o);
3488 o << ">\n";
3489
3490 write_function_decl(fn, ctxt,
3491 /*skip_first_parameter=*/false,
3492 get_indent_to_level(ctxt, indent, 2));
3493
3494 do_indent_to_level(ctxt, indent, 1);
3495 o << "</member-function>\n";
3496 }
3497
3498 for (member_function_templates::const_iterator fn =
3499 decl->get_member_function_templates().begin();
3500 fn != decl->get_member_function_templates().end();
3501 ++fn)
3502 {
3503 do_indent(o, nb_ws);
3504 o << "<member-template";
3505 write_access((*fn)->get_access_specifier(), o);
3506 write_cdtor_const_static((*fn)->is_constructor(),
3507 /*is_dtor=*/false,
3508 (*fn)->is_const(),
3509 (*fn)->get_is_static(), o);
3510 o << ">\n";
3511 write_function_tdecl((*fn)->as_function_tdecl(), ctxt,
3512 get_indent_to_level(ctxt, indent, 2));
3513 do_indent(o, nb_ws);
3514 o << "</member-template>\n";
3515 }
3516
3517 for (member_class_templates::const_iterator cl =
3518 decl->get_member_class_templates().begin();
3519 cl != decl->get_member_class_templates().end();
3520 ++cl)
3521 {
3522 do_indent(o, nb_ws);
3523 o << "<member-template";
3524 write_access((*cl)->get_access_specifier(), o);
3525 write_cdtor_const_static(false, false, false,
3526 (*cl)->get_is_static(), o);
3527 o << ">\n";
3528 write_class_tdecl((*cl)->as_class_tdecl(), ctxt,
3529 get_indent_to_level(ctxt, indent, 2));
3530 do_indent(o, nb_ws);
3531 o << "</member-template>\n";
3532 }
3533
3534 do_indent_to_level(ctxt, indent, 0);
3535
3536 o << "</class-decl>\n";
3537 }
3538
3539 ctxt.record_type_as_emitted(decl);
3540
3541 return true;
3542 }
3543
3544 /// Serialize a @ref union_decl type.
3545 ///
3546 /// @param d the pointer to @ref union_decl to serialize.
3547 ///
3548 /// @param ctxt the context of the serialization.
3549 ///
3550 /// @param indent the initial indentation to use.
3551 ///
3552 /// @return true upon successful completion.
3553 static bool
write_union_decl(const union_decl_sptr & d,write_context & ctxt,unsigned indent)3554 write_union_decl(const union_decl_sptr& d,
3555 write_context& ctxt,
3556 unsigned indent)
3557 {
3558 if (!d)
3559 return false;
3560
3561 union_decl_sptr decl = is_union_type(look_through_decl_only_class(d));
3562
3563 annotate(decl, ctxt, indent);
3564
3565 ostream& o = ctxt.get_ostream();
3566
3567 write_union_decl_opening_tag(decl, ctxt, indent,
3568 /*prepare_to_handle_members=*/true);
3569 if (!decl->has_no_member())
3570 {
3571 unsigned nb_ws = get_indent_to_level(ctxt, indent, 1);
3572 for (class_decl::member_types::const_iterator ti =
3573 decl->get_member_types().begin();
3574 ti != decl->get_member_types().end();
3575 ++ti)
3576 if (!(*ti)->get_naked_canonical_type())
3577 write_member_type(*ti, ctxt, nb_ws);
3578
3579 write_canonical_types_of_scope(*decl, ctxt, nb_ws,
3580 /*is_member_type=*/true);
3581
3582 for (union_decl::data_members::const_iterator data =
3583 decl->get_data_members().begin();
3584 data != decl->get_data_members().end();
3585 ++data)
3586 {
3587 do_indent(o, nb_ws);
3588 o << "<data-member";
3589 write_access(get_member_access_specifier(*data), o);
3590
3591 bool is_static = get_member_is_static(*data);
3592 write_cdtor_const_static(/*is_ctor=*/false,
3593 /*is_dtor=*/false,
3594 /*is_const=*/false,
3595 /*is_static=*/is_static,
3596 o);
3597 o << ">\n";
3598
3599 write_var_decl(*data, ctxt, is_static,
3600 get_indent_to_level(ctxt, indent, 2));
3601
3602 do_indent_to_level(ctxt, indent, 1);
3603 o << "</data-member>\n";
3604 }
3605
3606 for (union_decl::member_functions::const_iterator f =
3607 decl->get_member_functions().begin();
3608 f != decl->get_member_functions().end();
3609 ++f)
3610 {
3611 function_decl_sptr fn = *f;
3612 if (get_member_function_is_virtual(fn))
3613 // All virtual member functions are emitted together,
3614 // later.
3615 continue;
3616
3617 ABG_ASSERT(!get_member_function_is_virtual(fn));
3618
3619 do_indent(o, nb_ws);
3620 o << "<member-function";
3621 write_access(get_member_access_specifier(fn), o);
3622 write_cdtor_const_static( get_member_function_is_ctor(fn),
3623 get_member_function_is_dtor(fn),
3624 get_member_function_is_const(fn),
3625 get_member_is_static(fn),
3626 o);
3627 o << ">\n";
3628
3629 write_function_decl(fn, ctxt,
3630 /*skip_first_parameter=*/false,
3631 get_indent_to_level(ctxt, indent, 2));
3632
3633 do_indent_to_level(ctxt, indent, 1);
3634 o << "</member-function>\n";
3635 }
3636
3637 for (member_function_templates::const_iterator fn =
3638 decl->get_member_function_templates().begin();
3639 fn != decl->get_member_function_templates().end();
3640 ++fn)
3641 {
3642 do_indent(o, nb_ws);
3643 o << "<member-template";
3644 write_access((*fn)->get_access_specifier(), o);
3645 write_cdtor_const_static((*fn)->is_constructor(),
3646 /*is_dtor=*/false,
3647 (*fn)->is_const(),
3648 (*fn)->get_is_static(), o);
3649 o << ">\n";
3650 write_function_tdecl((*fn)->as_function_tdecl(), ctxt,
3651 get_indent_to_level(ctxt, indent, 2));
3652 do_indent(o, nb_ws);
3653 o << "</member-template>\n";
3654 }
3655
3656 for (member_class_templates::const_iterator cl =
3657 decl->get_member_class_templates().begin();
3658 cl != decl->get_member_class_templates().end();
3659 ++cl)
3660 {
3661 do_indent(o, nb_ws);
3662 o << "<member-template";
3663 write_access((*cl)->get_access_specifier(), o);
3664 write_cdtor_const_static(false, false, false,
3665 (*cl)->get_is_static(), o);
3666 o << ">\n";
3667 write_class_tdecl((*cl)->as_class_tdecl(), ctxt,
3668 get_indent_to_level(ctxt, indent, 2));
3669 do_indent(o, nb_ws);
3670 o << "</member-template>\n";
3671 }
3672
3673 do_indent_to_level(ctxt, indent, 0);
3674
3675 o << "</union-decl>\n";
3676 }
3677
3678 ctxt.record_type_as_emitted(decl);
3679
3680 return true;
3681 }
3682
3683 /// Write the opening tag for a 'member-type' element.
3684 ///
3685 /// @param t the member type to consider.
3686 ///
3687 /// @param ctxt the write context to use.
3688 ///
3689 /// @param indent the number of white spaces to use for indentation.
3690 ///
3691 /// @return true upon successful completion.
3692 static bool
write_member_type_opening_tag(const type_base_sptr & t,write_context & ctxt,unsigned indent)3693 write_member_type_opening_tag(const type_base_sptr& t,
3694 write_context& ctxt,
3695 unsigned indent)
3696 {
3697 ostream& o = ctxt.get_ostream();
3698
3699 do_indent_to_level(ctxt, indent, 0);
3700
3701 decl_base_sptr decl = get_type_declaration(t);
3702 ABG_ASSERT(decl);
3703
3704 o << "<member-type";
3705 write_access(decl, o);
3706 o << ">\n";
3707
3708 return true;
3709 }
3710
3711 /// Serialize a member type.
3712 ///
3713 /// @param decl the declaration of the member type to serialize.
3714 ///
3715 /// @param ctxt the write context to use.
3716 ///
3717 /// @param indent the number of levels to use for indentation
3718 static bool
write_member_type(const type_base_sptr & t,write_context & ctxt,unsigned indent)3719 write_member_type(const type_base_sptr& t, write_context& ctxt, unsigned indent)
3720 {
3721 if (!t)
3722 return false;
3723
3724 ostream& o = ctxt.get_ostream();
3725
3726 write_member_type_opening_tag(t, ctxt, indent);
3727
3728 unsigned nb_ws = get_indent_to_level(ctxt, indent, 1);
3729 ABG_ASSERT(write_qualified_type_def(dynamic_pointer_cast<qualified_type_def>(t),
3730 ctxt, nb_ws)
3731 || write_pointer_type_def(dynamic_pointer_cast<pointer_type_def>(t),
3732 ctxt, nb_ws)
3733 || write_reference_type_def(dynamic_pointer_cast<reference_type_def>(t),
3734 ctxt, nb_ws)
3735 || write_array_type_def(dynamic_pointer_cast<array_type_def>(t),
3736 ctxt, nb_ws)
3737 || write_enum_type_decl(dynamic_pointer_cast<enum_type_decl>(t),
3738 ctxt, nb_ws)
3739 || write_typedef_decl(dynamic_pointer_cast<typedef_decl>(t),
3740 ctxt, nb_ws)
3741 || write_union_decl(dynamic_pointer_cast<union_decl>(t),
3742 ctxt, nb_ws)
3743 || write_class_decl(dynamic_pointer_cast<class_decl>(t),
3744 ctxt, nb_ws));
3745
3746 do_indent_to_level(ctxt, indent, 0);
3747 o << "</member-type>\n";
3748
3749 return true;
3750 }
3751
3752 /// Serialize an instance of type_tparameter.
3753 ///
3754 /// @param decl the instance to serialize.
3755 ///
3756 /// @param ctxt the context of the serialization.
3757 ///
3758 /// @param indent the initial indentation to use.
3759 ///
3760 /// @return true upon successful completion, false otherwise.
3761 static bool
write_type_tparameter(const type_tparameter_sptr decl,write_context & ctxt,unsigned indent)3762 write_type_tparameter(const type_tparameter_sptr decl,
3763 write_context& ctxt,
3764 unsigned indent)
3765 {
3766 if (!decl)
3767 return false;
3768
3769 ostream &o = ctxt.get_ostream();
3770 do_indent_to_level(ctxt, indent, 0);
3771
3772 string id_attr_name;
3773 if (ctxt.type_has_existing_id(decl))
3774 id_attr_name = "type-id";
3775 else
3776 id_attr_name = "id";
3777
3778 o << "<template-type-parameter "
3779 << id_attr_name << "='" << ctxt.get_id_for_type(decl) << "'";
3780
3781 std::string name = xml::escape_xml_string(decl->get_name ());
3782 if (!name.empty())
3783 o << " name='" << name << "'";
3784
3785 write_location(decl, ctxt);
3786
3787 o << "/>\n";
3788
3789 ctxt.record_type_as_emitted(decl);
3790
3791 return true;
3792 }
3793
3794 /// Serialize an instance of non_type_tparameter.
3795 ///
3796 /// @param decl the instance to serialize.
3797 ///
3798 /// @param ctxt the context of the serialization.
3799 ///
3800 /// @param indent the intial indentation to use.
3801 ///
3802 /// @return true open successful completion, false otherwise.
3803 static bool
write_non_type_tparameter(const shared_ptr<non_type_tparameter> decl,write_context & ctxt,unsigned indent)3804 write_non_type_tparameter(
3805 const shared_ptr<non_type_tparameter> decl,
3806 write_context& ctxt, unsigned indent)
3807 {
3808 if (!decl)
3809 return false;
3810
3811 ostream &o = ctxt.get_ostream();
3812 do_indent_to_level(ctxt, indent, 0);
3813
3814 o << "<template-non-type-parameter type-id='"
3815 << ctxt.get_id_for_type(decl->get_type())
3816 << "'";
3817
3818 string name = xml::escape_xml_string(decl->get_name());
3819 if (!name.empty())
3820 o << " name='" << name << "'";
3821
3822 write_location(decl, ctxt);
3823
3824 o << "/>\n";
3825
3826 return true;
3827 }
3828
3829 /// Serialize an instance of template template parameter.
3830 ///
3831 /// @param decl the instance to serialize.
3832 ///
3833 /// @param ctxt the context of the serialization.
3834 ///
3835 /// @param indent the initial indentation to use.
3836 ///
3837 /// @return true upon successful completion, false otherwise.
3838
3839 static bool
write_template_tparameter(const template_tparameter_sptr decl,write_context & ctxt,unsigned indent)3840 write_template_tparameter (const template_tparameter_sptr decl,
3841 write_context& ctxt,
3842 unsigned indent)
3843 {
3844 if (!decl)
3845 return false;
3846
3847 ostream& o = ctxt.get_ostream();
3848 do_indent_to_level(ctxt, indent, 0);
3849
3850 string id_attr_name = "id";
3851 if (ctxt.type_has_existing_id(decl))
3852 id_attr_name = "type-id";
3853
3854 o << "<template-template-parameter " << id_attr_name << "='"
3855 << ctxt.get_id_for_type(decl) << "'";
3856
3857 string name = xml::escape_xml_string(decl->get_name());
3858 if (!name.empty())
3859 o << " name='" << name << "'";
3860
3861 o << ">\n";
3862
3863 unsigned nb_spaces = get_indent_to_level(ctxt, indent, 1);
3864 for (list<shared_ptr<template_parameter> >::const_iterator p =
3865 decl->get_template_parameters().begin();
3866 p != decl->get_template_parameters().end();
3867 ++p)
3868 write_template_parameter(decl, ctxt, nb_spaces);
3869
3870 do_indent_to_level(ctxt, indent, 0);
3871 o << "</template-template-parameter>\n";
3872
3873 ctxt.record_type_as_emitted(decl);
3874
3875 return true;
3876 }
3877
3878 /// Serialize an instance of type_composition.
3879 ///
3880 /// @param decl the decl to serialize.
3881 ///
3882 /// @param ctxt the context of the serialization.
3883 ///
3884 /// @param indent the initial indentation to use.
3885 ///
3886 /// @return true upon successful completion, false otherwise.
3887 static bool
write_type_composition(const shared_ptr<type_composition> decl,write_context & ctxt,unsigned indent)3888 write_type_composition
3889 (const shared_ptr<type_composition> decl,
3890 write_context& ctxt, unsigned indent)
3891 {
3892 if (!decl)
3893 return false;
3894
3895 ostream& o = ctxt.get_ostream();
3896
3897 do_indent_to_level(ctxt, indent, 0);
3898
3899 o << "<template-parameter-type-composition>\n";
3900
3901 unsigned nb_spaces = get_indent_to_level(ctxt, indent, 1);
3902 (write_pointer_type_def
3903 (dynamic_pointer_cast<pointer_type_def>(decl->get_composed_type()),
3904 ctxt, nb_spaces)
3905 || write_reference_type_def
3906 (dynamic_pointer_cast<reference_type_def>(decl->get_composed_type()),
3907 ctxt, nb_spaces)
3908 || write_array_type_def
3909 (dynamic_pointer_cast<array_type_def>(decl->get_composed_type()),
3910 ctxt, nb_spaces)
3911 || write_qualified_type_def
3912 (dynamic_pointer_cast<qualified_type_def>(decl->get_composed_type()),
3913 ctxt, nb_spaces));
3914
3915 do_indent_to_level(ctxt, indent, 0);
3916 o << "</template-parameter-type-composition>\n";
3917
3918 return true;
3919 }
3920
3921 /// Serialize an instance of template_parameter.
3922 ///
3923 /// @param decl the instance to serialize.
3924 ///
3925 /// @param ctxt the context of the serialization.
3926 ///
3927 /// @param indent the initial indentation to use.
3928 ///
3929 /// @return true upon successful completion, false otherwise.
3930 static bool
write_template_parameter(const shared_ptr<template_parameter> decl,write_context & ctxt,unsigned indent)3931 write_template_parameter(const shared_ptr<template_parameter> decl,
3932 write_context& ctxt, unsigned indent)
3933 {
3934 if ((!write_type_tparameter
3935 (dynamic_pointer_cast<type_tparameter>(decl), ctxt, indent))
3936 && (!write_non_type_tparameter
3937 (dynamic_pointer_cast<non_type_tparameter>(decl),
3938 ctxt, indent))
3939 && (!write_template_tparameter
3940 (dynamic_pointer_cast<template_tparameter>(decl),
3941 ctxt, indent))
3942 && (!write_type_composition
3943 (dynamic_pointer_cast<type_composition>(decl),
3944 ctxt, indent)))
3945 return false;
3946
3947 return true;
3948 }
3949
3950 /// Serialize the template parameters of the a given template.
3951 ///
3952 /// @param tmpl the template for which to emit the template parameters.
3953 static void
write_template_parameters(const shared_ptr<template_decl> tmpl,write_context & ctxt,unsigned indent)3954 write_template_parameters(const shared_ptr<template_decl> tmpl,
3955 write_context& ctxt, unsigned indent)
3956 {
3957 if (!tmpl)
3958 return;
3959
3960 unsigned nb_spaces = get_indent_to_level(ctxt, indent, 1);
3961 for (list<shared_ptr<template_parameter> >::const_iterator p =
3962 tmpl->get_template_parameters().begin();
3963 p != tmpl->get_template_parameters().end();
3964 ++p)
3965 write_template_parameter(*p, ctxt, nb_spaces);
3966 }
3967
3968 /// Serialize an instance of function_tdecl.
3969 ///
3970 /// @param decl the instance to serialize.
3971 ///
3972 /// @param ctxt the context of the serialization
3973 ///
3974 /// @param indent the initial indentation.
3975 static bool
write_function_tdecl(const shared_ptr<function_tdecl> decl,write_context & ctxt,unsigned indent)3976 write_function_tdecl(const shared_ptr<function_tdecl> decl,
3977 write_context& ctxt, unsigned indent)
3978 {
3979 if (!decl)
3980 return false;
3981
3982 ostream& o = ctxt.get_ostream();
3983
3984 do_indent_to_level(ctxt, indent, 0);
3985
3986 o << "<function-template-decl id='" << ctxt.get_id_for_fn_tmpl(decl) << "'";
3987
3988 write_location(decl, ctxt);
3989
3990 write_visibility(decl, o);
3991
3992 write_binding(decl, o);
3993
3994 o << ">\n";
3995
3996 write_template_parameters(decl, ctxt, indent);
3997
3998 write_function_decl(decl->get_pattern(), ctxt,
3999 /*skip_first_parameter=*/false,
4000 get_indent_to_level(ctxt, indent, 1));
4001
4002 do_indent_to_level(ctxt, indent, 0);
4003
4004 o << "</function-template-decl>\n";
4005
4006 return true;
4007 }
4008
4009
4010 /// Serialize an instance of class_tdecl
4011 ///
4012 /// @param decl a pointer to the instance of class_tdecl to serialize.
4013 ///
4014 /// @param ctxt the context of the serializtion.
4015 ///
4016 /// @param indent the initial number of white space to use for
4017 /// indentation.
4018 ///
4019 /// @return true upon successful completion, false otherwise.
4020 static bool
write_class_tdecl(const shared_ptr<class_tdecl> decl,write_context & ctxt,unsigned indent)4021 write_class_tdecl(const shared_ptr<class_tdecl> decl,
4022 write_context& ctxt, unsigned indent)
4023 {
4024 if (!decl)
4025 return false;
4026
4027 ostream& o = ctxt.get_ostream();
4028
4029 do_indent_to_level(ctxt, indent, 0);
4030
4031 o << "<class-template-decl id='" << ctxt.get_id_for_class_tmpl(decl) << "'";
4032
4033 write_location(decl, ctxt);
4034
4035 write_visibility(decl, o);
4036
4037 o << ">\n";
4038
4039 write_template_parameters(decl, ctxt, indent);
4040
4041 write_class_decl(decl->get_pattern(), ctxt,
4042 get_indent_to_level(ctxt, indent, 1));
4043
4044 do_indent_to_level(ctxt, indent, 0);
4045
4046 o << "</class-template-decl>\n";
4047
4048 return true;
4049 }
4050
4051 /// Serialize the current version number of the ABIXML format.
4052 ///
4053 /// @param ctxt the writing context to use.
4054 static void
write_version_info(write_context & ctxt)4055 write_version_info(write_context& ctxt)
4056 {
4057 ostream& o = ctxt.get_ostream();
4058 const config& c = ctxt.get_config();
4059
4060 o << "version='"
4061 << c.get_format_major_version_number()
4062 << "." << c.get_format_minor_version_number()
4063 << "'";
4064 }
4065
4066 /// Serialize an ABI corpus to a single native xml document. The root
4067 /// note of the resulting XML document is 'abi-corpus'.
4068 ///
4069 /// Note: If either corpus is null or corpus does not contain serializable
4070 /// content (i.e. corpus.is_empty()), nothing is emitted to the ctxt's
4071 /// output stream.
4072 ///
4073 /// @param ctxt the write context to use.
4074 ///
4075 /// @param corpus the corpus to serialize.
4076 ///
4077 /// @param indent the number of white space indentation to use.
4078 ///
4079 /// @return true upon successful completion, false otherwise.
4080 bool
write_corpus(write_context & ctxt,const corpus_sptr & corpus,unsigned indent,bool member_of_group)4081 write_corpus(write_context& ctxt,
4082 const corpus_sptr& corpus,
4083 unsigned indent,
4084 bool member_of_group)
4085 {
4086 if (!corpus)
4087 return false;
4088
4089 if (corpus->is_empty())
4090 return true;
4091
4092 do_indent_to_level(ctxt, indent, 0);
4093
4094 std::ostream& out = ctxt.get_ostream();
4095
4096 out << "<abi-corpus ";
4097
4098 write_version_info(ctxt);
4099
4100 // For an abi-corpus as part of an abi-corpus group, only omit the path, but
4101 // keep the filename.
4102 std::string corpus_path = corpus->get_path();
4103 if (!ctxt.get_write_corpus_path())
4104 {
4105 if (member_of_group)
4106 tools_utils::base_name(corpus_path, corpus_path);
4107 else
4108 corpus_path.clear();
4109 }
4110 else
4111 {
4112 if (ctxt.get_short_locs())
4113 tools_utils::base_name(corpus_path, corpus_path);
4114 }
4115 if (!corpus_path.empty())
4116 out << " path='" << xml::escape_xml_string(corpus_path) << "'";
4117
4118 if (!corpus->get_architecture_name().empty()
4119 && ctxt.get_write_architecture())
4120 out << " architecture='" << corpus->get_architecture_name()<< "'";
4121
4122 if (!corpus->get_soname().empty())
4123 out << " soname='" << corpus->get_soname()<< "'";
4124
4125 write_tracking_non_reachable_types(corpus, out);
4126
4127 out << ">\n";
4128
4129 // Write the list of needed corpora.
4130
4131 if (ctxt.get_write_elf_needed () && !corpus->get_needed().empty())
4132 {
4133 do_indent_to_level(ctxt, indent, 1);
4134 out << "<elf-needed>\n";
4135 write_elf_needed(corpus->get_needed(), ctxt,
4136 get_indent_to_level(ctxt, indent, 2));
4137 do_indent_to_level(ctxt, indent, 1);
4138 out << "</elf-needed>\n";
4139 }
4140
4141 // Write the function symbols data base.
4142 if (!corpus->get_fun_symbol_map().empty())
4143 {
4144 do_indent_to_level(ctxt, indent, 1);
4145 out << "<elf-function-symbols>\n";
4146
4147 write_elf_symbols_table(corpus->get_sorted_fun_symbols(), ctxt,
4148 get_indent_to_level(ctxt, indent, 2));
4149
4150 do_indent_to_level(ctxt, indent, 1);
4151 out << "</elf-function-symbols>\n";
4152 }
4153
4154 // Write the variable symbols data base.
4155 if (!corpus->get_var_symbol_map().empty())
4156 {
4157 do_indent_to_level(ctxt, indent, 1);
4158 out << "<elf-variable-symbols>\n";
4159
4160 write_elf_symbols_table(corpus->get_sorted_var_symbols(), ctxt,
4161 get_indent_to_level(ctxt, indent, 2));
4162
4163 do_indent_to_level(ctxt, indent, 1);
4164 out << "</elf-variable-symbols>\n";
4165 }
4166
4167 // Now write the translation units.
4168 unsigned nb_tus = corpus->get_translation_units().size(), n = 0;
4169 for (translation_units::const_iterator i =
4170 corpus->get_translation_units().begin();
4171 i != corpus->get_translation_units().end();
4172 ++i, ++n)
4173 {
4174 translation_unit& tu = **i;
4175 write_translation_unit(ctxt, tu,
4176 get_indent_to_level(ctxt, indent, 1),
4177 n == nb_tus - 1);
4178 }
4179
4180 do_indent_to_level(ctxt, indent, 0);
4181 out << "</abi-corpus>\n";
4182
4183 ctxt.clear_referenced_types();
4184
4185 return true;
4186 }
4187
4188 /// Serialize an ABI corpus group to a single native xml document.
4189 /// The root note of the resulting XML document is 'abi-corpus-group'.
4190 ///
4191 /// @param ctxt the write context to use.
4192 ///
4193 /// @param group the corpus group to serialize.
4194 ///
4195 /// @param indent the number of white space indentation to use.
4196 ///
4197 /// @return true upon successful completion, false otherwise.
4198 bool
write_corpus_group(write_context & ctxt,const corpus_group_sptr & group,unsigned indent)4199 write_corpus_group(write_context& ctxt,
4200 const corpus_group_sptr& group,
4201 unsigned indent)
4202
4203 {
4204 if (!group)
4205 return false;
4206
4207 do_indent_to_level(ctxt, indent, 0);
4208
4209 std::ostream& out = ctxt.get_ostream();
4210
4211 out << "<abi-corpus-group ";
4212 write_version_info(ctxt);
4213
4214 if (!group->get_path().empty() && ctxt.get_write_corpus_path())
4215 out << " path='" << xml::escape_xml_string(group->get_path()) << "'";
4216
4217 if (!group->get_architecture_name().empty() && ctxt.get_write_architecture())
4218 out << " architecture='" << group->get_architecture_name()<< "'";
4219
4220 write_tracking_non_reachable_types(group, out);
4221
4222 if (group->is_empty())
4223 {
4224 out << "/>\n";
4225 return true;
4226 }
4227
4228 out << ">\n";
4229
4230 // Write the list of corpora
4231 for (corpus_group::corpora_type::const_iterator c =
4232 group->get_corpora().begin();
4233 c != group->get_corpora().end();
4234 ++c)
4235 write_corpus(ctxt, *c, get_indent_to_level(ctxt, indent, 1), true);
4236
4237 do_indent_to_level(ctxt, indent, 0);
4238 out << "</abi-corpus-group>\n";
4239
4240 return true;
4241 }
4242
4243 } //end namespace xml_writer
4244
4245 // <Debugging routines>
4246
4247 using namespace abigail::ir;
4248
4249 /// Serialize a pointer to decl_base to an output stream.
4250 ///
4251 /// @param d the pointer to decl_base to serialize.
4252 ///
4253 /// @param o the output stream to consider.
4254 ///
4255 /// @param annotate whether ABIXML output should be annotated.
4256 void
dump(const decl_base_sptr d,std::ostream & o,const bool annotate)4257 dump(const decl_base_sptr d, std::ostream& o, const bool annotate)
4258 {
4259 xml_writer::write_context ctxt(d->get_environment(), o);
4260 xml_writer::set_annotate(ctxt, annotate);
4261 write_decl(d, ctxt, /*indent=*/0);
4262 }
4263
4264 /// Serialize a pointer to decl_base to stderr.
4265 ///
4266 /// @param d the pointer to decl_base to serialize.
4267 ///
4268 /// @param annotate whether ABIXML output should be annotated.
4269 void
dump(const decl_base_sptr d,const bool annotate)4270 dump(const decl_base_sptr d, const bool annotate)
4271 {dump(d, cerr, annotate);}
4272
4273 /// Serialize a pointer to type_base to an output stream.
4274 ///
4275 /// @param t the pointer to type_base to serialize.
4276 ///
4277 /// @param o the output stream to serialize the @ref type_base to.
4278 ///
4279 /// @param annotate whether ABIXML output should be annotated.
4280 void
dump(const type_base_sptr t,std::ostream & o,const bool annotate)4281 dump(const type_base_sptr t, std::ostream& o, const bool annotate)
4282 {dump(get_type_declaration(t), o, annotate);}
4283
4284 /// Serialize a pointer to type_base to stderr.
4285 ///
4286 /// @param t the pointer to type_base to serialize.
4287 ///
4288 /// @param annotate whether ABIXML output should be annotated.
4289 void
dump(const type_base_sptr t,const bool annotate)4290 dump(const type_base_sptr t, const bool annotate)
4291 {dump(t, cerr, annotate);}
4292
4293 /// Serialize a pointer to var_decl to an output stream.
4294 ///
4295 /// @param v the pointer to var_decl to serialize.
4296 ///
4297 /// @param o the output stream to serialize the @ref var_decl to.
4298 ///
4299 /// @param annotate whether ABIXML output should be annotated.
4300 void
dump(const var_decl_sptr v,std::ostream & o,const bool annotate)4301 dump(const var_decl_sptr v, std::ostream& o, const bool annotate)
4302 {
4303 xml_writer::write_context ctxt(v->get_environment(), o);
4304 xml_writer::set_annotate(ctxt, annotate);
4305 write_var_decl(v, ctxt, /*linkage_name*/true, /*indent=*/0);
4306 }
4307
4308 /// Serialize a pointer to var_decl to stderr.
4309 ///
4310 /// @param v the pointer to var_decl to serialize.
4311 ///
4312 /// @param annotate whether ABIXML output should be annotated.
4313 void
dump(const var_decl_sptr v,const bool annotate)4314 dump(const var_decl_sptr v, const bool annotate)
4315 {dump(v, cerr, annotate);}
4316
4317 /// Serialize a @ref translation_unit to an output stream.
4318 ///
4319 /// @param t the translation_unit to serialize.
4320 ///
4321 /// @param o the outpout stream to serialize the translation_unit to.
4322 ///
4323 /// @param annotate whether ABIXML output should be annotated.
4324 void
dump(const translation_unit & t,std::ostream & o,const bool annotate)4325 dump(const translation_unit& t, std::ostream& o, const bool annotate)
4326 {
4327 xml_writer::write_context ctxt(t.get_environment(), o);
4328 xml_writer::set_annotate(ctxt, annotate);
4329 write_translation_unit(ctxt, t, /*indent=*/0);
4330 }
4331
4332 /// Serialize an instance of @ref translation_unit to stderr.
4333 ///
4334 /// @param t the translation_unit to serialize.
4335 void
dump(const translation_unit & t,const bool annotate)4336 dump(const translation_unit& t, const bool annotate)
4337 {dump(t, cerr, annotate);}
4338
4339 /// Serialize a pointer to @ref translation_unit to an output stream.
4340 ///
4341 /// @param t the @ref translation_unit_sptr to serialize.
4342 ///
4343 /// @param o the output stream to serialize the translation unit to.
4344 ///
4345 /// @param annotate whether ABIXML output should be annotated.
4346 void
dump(const translation_unit_sptr t,std::ostream & o,const bool annotate)4347 dump(const translation_unit_sptr t, std::ostream& o, const bool annotate)
4348 {
4349 if (t)
4350 dump(*t, o, annotate);
4351 }
4352
4353 /// Serialize a pointer to @ref translation_unit to stderr.
4354 ///
4355 /// @param t the translation_unit_sptr to serialize.
4356 ///
4357 /// @param annotate whether ABIXML output should be annotated.
4358 void
dump(const translation_unit_sptr t,const bool annotate)4359 dump(const translation_unit_sptr t, const bool annotate)
4360 {
4361 if (t)
4362 dump(*t, annotate);
4363 }
4364
4365 /// Serialize a source location to an output stream.
4366 ///
4367 /// @param l the declaration to consider.
4368 ///
4369 /// @param o the output stream to serialize to.
4370 void
dump_location(const location & l,ostream & o)4371 dump_location(const location& l, ostream& o)
4372 {
4373 string path;
4374 unsigned line = 0, col = 0;
4375
4376 l.expand(path, line, col);
4377 o << path << ":" << line << "," << col << "\n";
4378 }
4379
4380 /// Serialize a source location for debugging purposes.
4381 ///
4382 /// The location is serialized to the standard error output stream.
4383 ///
4384 /// @param l the declaration to consider.
4385 ///
4386 void
dump_location(const location & l)4387 dump_location(const location& l)
4388 {dump_location(l, cerr);}
4389
4390 /// Serialize the source location of a decl to an output stream for
4391 /// debugging purposes.
4392 ///
4393 /// @param d the declaration to consider.
4394 ///
4395 /// @param o the output stream to serizalize the location to.
4396 void
dump_decl_location(const decl_base & d,ostream & o)4397 dump_decl_location(const decl_base& d, ostream& o)
4398 {dump_location(d.get_location(), o);}
4399
4400 /// Serialize the source location of a decl to stderr for debugging
4401 /// purposes.
4402 ///
4403 /// @param d the declaration to consider.
4404 void
dump_decl_location(const decl_base & d)4405 dump_decl_location(const decl_base& d)
4406 {dump_decl_location(d, cerr);}
4407
4408 /// Serialize the source location of a dcl to stderr for debugging
4409 /// purposes.
4410 ///
4411 /// @param d the declaration to consider.
4412 void
dump_decl_location(const decl_base * d)4413 dump_decl_location(const decl_base* d)
4414 {
4415 if (d)
4416 dump_decl_location(*d);
4417 }
4418
4419 /// Serialize the source location of a decl to stderr for debugging
4420 /// purposes.
4421 ///
4422 /// @param d the declaration to consider.
4423 void
dump_decl_location(const decl_base_sptr d)4424 dump_decl_location(const decl_base_sptr d)
4425 {dump_decl_location(d.get());}
4426
4427 #ifdef WITH_DEBUG_SELF_COMPARISON
4428 /// Write one of the records of the "type-ids" debugging file.
4429 ///
4430 /// This is a sub-routine of write_canonical_type_ids.
4431 ///
4432 /// @param ctxt the context to use.
4433 ///
4434 /// @param type the type which canonical type pointer value to emit.
4435 ///
4436 /// @param o the output stream to write to.
4437 static void
write_type_record(xml_writer::write_context & ctxt,const type_base * type,ostream & o)4438 write_type_record(xml_writer::write_context& ctxt,
4439 const type_base* type,
4440 ostream& o)
4441 {
4442 // We want to serialize a type record which content looks like:
4443 //
4444 // <type>
4445 // <id>type-id-573</id>
4446 // <c>0x262ee28</c>
4447 // </type>
4448 // <type>
4449 // <id>type-id-569</id>
4450 // <c>0x2628298</c>
4451 // </type>
4452 // <type>
4453 // <id>type-id-575</id>
4454 // <c>0x25f9ba8</c>
4455 // </type>
4456
4457 string id = ctxt.get_id_for_type (const_cast<type_base*>(type));
4458 o << " <type>\n"
4459 << " <id>" << id << "</id>\n"
4460 << " <c>"
4461 << std::hex
4462 << (type->get_canonical_type()
4463 ? reinterpret_cast<uintptr_t>(type->get_canonical_type().get())
4464 : 0xdeadbabe)
4465 << "</c>\n"
4466 << " </type>\n";
4467 }
4468
4469 /// Serialize the map that is stored at
4470 /// environment::get_type_id_canonical_type_map() to an output stream.
4471 ///
4472 /// This is for debugging purposes and is triggered ultimately by
4473 /// invoking the command 'abidw --debug-abidiff <binary>'.
4474 ///
4475 /// @param ctxt the write context.
4476 ///
4477 /// @param o the output stream to serialize the map to.
4478 void
write_canonical_type_ids(xml_writer::write_context & ctxt,ostream & o)4479 write_canonical_type_ids(xml_writer::write_context& ctxt, ostream& o)
4480 {
4481 // We want to serialize a file which content looks like:
4482 //
4483 // <abixml-types-check>
4484 // <type>
4485 // <id>type-id-573</id>
4486 // <c>0x262ee28</c>
4487 // </type>
4488 // <type>
4489 // <id>type-id-569</id>
4490 // <c>0x2628298</c>
4491 // </type>
4492 // <type>
4493 // <id>type-id-575</id>
4494 // <c>0x25f9ba8</c>
4495 // </type>
4496 // <abixml-types-check>
4497
4498 o << "<abixml-types-check>\n";
4499
4500 for (const auto &type : ctxt.get_emitted_types_set())
4501 write_type_record(ctxt, type, o);
4502
4503 o << "</abixml-types-check>\n";
4504 }
4505
4506 /// Serialize the map that is stored at
4507 /// environment::get_type_id_canonical_type_map() to a file.
4508 ///
4509 /// This is for debugging purposes and is triggered ultimately by
4510 /// invoking the command 'abidw --debug-abidiff <binary>'.
4511 ///
4512 /// @param ctxt the write context.
4513 ///
4514 /// @param file_path the file to serialize the map to.
4515 bool
write_canonical_type_ids(xml_writer::write_context & ctxt,const string & file_path)4516 write_canonical_type_ids(xml_writer::write_context& ctxt,
4517 const string &file_path)
4518 {
4519 std:: ofstream o (file_path);
4520
4521 if (!o.is_open())
4522 return true;
4523 write_canonical_type_ids(ctxt, o);
4524 o.close();
4525 return true;
4526 }
4527 #endif
4528 // </Debugging routines>
4529 } //end namespace abigail
4530