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