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