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