]> git.ipfire.org Git - thirdparty/gcc.git/blame - libstdc++-v3/src/c++11/debug.cc
[multiple changes]
[thirdparty/gcc.git] / libstdc++-v3 / src / c++11 / debug.cc
CommitLineData
285b36d6
BK
1// Debugging mode support code -*- C++ -*-
2
77e0bf4e
FD
3// Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
4// 2011 Free Software Foundation, Inc.
285b36d6
BK
5//
6// This file is part of the GNU ISO C++ Library. This library is free
7// software; you can redistribute it and/or modify it under the
8// terms of the GNU General Public License as published by the
748086b7 9// Free Software Foundation; either version 3, or (at your option)
285b36d6
BK
10// any later version.
11
12// This library is distributed in the hope that it will be useful,
13// but WITHOUT ANY WARRANTY; without even the implied warranty of
14// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15// GNU General Public License for more details.
16
748086b7
JJ
17// Under Section 7 of GPL version 3, you are granted additional
18// permissions described in the GCC Runtime Library Exception, version
19// 3.1, as published by the Free Software Foundation.
285b36d6 20
748086b7
JJ
21// You should have received a copy of the GNU General Public License and
22// a copy of the GCC Runtime Library Exception along with this program;
23// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
24// <http://www.gnu.org/licenses/>.
285b36d6
BK
25
26#include <debug/debug.h>
27#include <debug/safe_sequence.h>
364c862b 28#include <debug/safe_unordered_container.h>
285b36d6 29#include <debug/safe_iterator.h>
77e0bf4e 30#include <debug/safe_local_iterator.h>
285b36d6 31#include <algorithm>
285b36d6
BK
32#include <cassert>
33#include <cstring>
285b36d6 34#include <cctype>
39b8cd70 35#include <cstdio>
5dddb7e5 36#include <cstdlib>
afe96d41 37#include <functional>
285b36d6
BK
38
39using namespace std;
40
b82f782b 41namespace
656cee9a 42{
afe96d41
FD
43 /** Returns different instances of __mutex depending on the passed address
44 * in order to limit contention without breaking current library binary
45 * compatibility. */
99827523 46 __gnu_cxx::__mutex&
afe96d41 47 get_safe_base_mutex(void* __address)
99827523 48 {
afe96d41
FD
49 const size_t mask = 0xf;
50 static __gnu_cxx::__mutex safe_base_mutex[mask + 1];
51 const size_t index = _Hash_impl::hash(__address) & mask;
52 return safe_base_mutex[index];
53 }
54
55 void
77e0bf4e
FD
56 swap_its(__gnu_debug::_Safe_sequence_base& __lhs,
57 __gnu_debug::_Safe_iterator_base*& __lhs_its,
58 __gnu_debug::_Safe_sequence_base& __rhs,
59 __gnu_debug::_Safe_iterator_base*& __rhs_its)
afe96d41 60 {
77e0bf4e 61 swap(__lhs_its, __rhs_its);
afe96d41 62 __gnu_debug::_Safe_iterator_base* __iter;
77e0bf4e 63 for (__iter = __rhs_its; __iter; __iter = __iter->_M_next)
afe96d41 64 __iter->_M_sequence = &__rhs;
77e0bf4e 65 for (__iter = __lhs_its; __iter; __iter = __iter->_M_next)
afe96d41 66 __iter->_M_sequence = &__lhs;
99827523 67 }
77e0bf4e
FD
68
69 void
70 swap_seq(__gnu_debug::_Safe_sequence_base& __lhs,
71 __gnu_debug::_Safe_sequence_base& __rhs)
72 {
73 swap(__lhs._M_version, __rhs._M_version);
74 swap_its(__lhs, __lhs._M_iterators,
75 __rhs, __rhs._M_iterators);
76 swap_its(__lhs, __lhs._M_const_iterators,
77 __rhs, __rhs._M_const_iterators);
78 }
79
80 void
364c862b
FD
81 swap_ucont(__gnu_debug::_Safe_unordered_container_base& __lhs,
82 __gnu_debug::_Safe_unordered_container_base& __rhs)
77e0bf4e
FD
83 {
84 swap_seq(__lhs, __rhs);
85 swap_its(__lhs, __lhs._M_local_iterators,
86 __rhs, __rhs._M_local_iterators);
87 swap_its(__lhs, __lhs._M_const_local_iterators,
88 __rhs, __rhs._M_const_local_iterators);
89 }
90
91 void
92 detach_all(__gnu_debug::_Safe_iterator_base* __iter)
93 {
94 for (; __iter;)
95 {
96 __gnu_debug::_Safe_iterator_base* __old = __iter;
97 __iter = __iter->_M_next;
98 __old->_M_reset();
99 }
100 }
2e362c74 101} // anonymous namespace
656cee9a 102
285b36d6
BK
103namespace __gnu_debug
104{
105 const char* _S_debug_messages[] =
106 {
77e0bf4e 107 // General Checks
285b36d6
BK
108 "function requires a valid iterator range [%1.name;, %2.name;)",
109 "attempt to insert into container with a singular iterator",
4be58168
BK
110 "attempt to insert into container with an iterator"
111 " from a different container",
285b36d6 112 "attempt to erase from container with a %2.state; iterator",
4be58168
BK
113 "attempt to erase from container with an iterator"
114 " from a different container",
115 "attempt to subscript container with out-of-bounds index %2;,"
116 " but container only holds %3; elements",
285b36d6 117 "attempt to access an element in an empty container",
4be58168
BK
118 "elements in iterator range [%1.name;, %2.name;)"
119 " are not partitioned by the value %3;",
120 "elements in iterator range [%1.name;, %2.name;)"
121 " are not partitioned by the predicate %3; and value %4;",
285b36d6 122 "elements in iterator range [%1.name;, %2.name;) are not sorted",
4be58168
BK
123 "elements in iterator range [%1.name;, %2.name;)"
124 " are not sorted according to the predicate %3;",
285b36d6 125 "elements in iterator range [%1.name;, %2.name;) do not form a heap",
4be58168
BK
126 "elements in iterator range [%1.name;, %2.name;)"
127 " do not form a heap with respect to the predicate %3;",
77e0bf4e 128 // std::bitset checks
285b36d6
BK
129 "attempt to write through a singular bitset reference",
130 "attempt to read from a singular bitset reference",
131 "attempt to flip a singular bitset reference",
77e0bf4e 132 // std::list checks
285b36d6
BK
133 "attempt to splice a list into itself",
134 "attempt to splice lists with inequal allocators",
135 "attempt to splice elements referenced by a %1.state; iterator",
136 "attempt to splice an iterator from a different container",
4be58168
BK
137 "splice destination %1.name;"
138 " occurs within source range [%2.name;, %3.name;)",
77e0bf4e 139 // iterator checks
285b36d6
BK
140 "attempt to initialize an iterator that will immediately become singular",
141 "attempt to copy-construct an iterator from a singular iterator",
4be58168
BK
142 "attempt to construct a constant iterator"
143 " from a singular mutable iterator",
285b36d6
BK
144 "attempt to copy from a singular iterator",
145 "attempt to dereference a %1.state; iterator",
146 "attempt to increment a %1.state; iterator",
147 "attempt to decrement a %1.state; iterator",
4be58168
BK
148 "attempt to subscript a %1.state; iterator %2; step from"
149 " its current position, which falls outside its dereferenceable range",
150 "attempt to advance a %1.state; iterator %2; steps,"
151 " which falls outside its valid range",
152 "attempt to retreat a %1.state; iterator %2; steps,"
153 " which falls outside its valid range",
285b36d6
BK
154 "attempt to compare a %1.state; iterator to a %2.state; iterator",
155 "attempt to compare iterators from different sequences",
156 "attempt to order a %1.state; iterator to a %2.state; iterator",
157 "attempt to order iterators from different sequences",
4be58168
BK
158 "attempt to compute the difference between a %1.state;"
159 " iterator to a %2.state; iterator",
160 "attempt to compute the different between two iterators"
161 " from different sequences",
77e0bf4e 162 // istream_iterator
285b36d6
BK
163 "attempt to dereference an end-of-stream istream_iterator",
164 "attempt to increment an end-of-stream istream_iterator",
77e0bf4e 165 // ostream_iterator
285b36d6 166 "attempt to output via an ostream_iterator with no associated stream",
77e0bf4e 167 // istreambuf_iterator
4be58168
BK
168 "attempt to dereference an end-of-stream istreambuf_iterator"
169 " (this is a GNU extension)",
b8b4301e 170 "attempt to increment an end-of-stream istreambuf_iterator",
77e0bf4e 171 // std::forward_list
b8b4301e
PC
172 "attempt to insert into container after an end iterator",
173 "attempt to erase from container after a %2.state; iterator not followed"
174 " by a dereferenceable one",
68478bb4 175 "function requires a valid iterator range (%2.name;, %3.name;)"
77e0bf4e 176 ", \"%2.name;\" shall be before and not equal to \"%3.name;\"",
364c862b
FD
177 // std::unordered_container::local_iterator
178 "attempt to compare local iterators from different unordered container"
a8028a3e
JW
179 " buckets",
180 "function requires a non-empty iterator range [%1.name;, %2.name;)"
285b36d6
BK
181 };
182
eebbe2c7 183 void
285b36d6
BK
184 _Safe_sequence_base::
185 _M_detach_all()
186 {
99827523 187 __gnu_cxx::__scoped_lock sentry(_M_get_mutex());
77e0bf4e 188 detach_all(_M_iterators);
afe96d41 189 _M_iterators = 0;
285b36d6 190
77e0bf4e 191 detach_all(_M_const_iterators);
afe96d41 192 _M_const_iterators = 0;
285b36d6
BK
193 }
194
eebbe2c7 195 void
285b36d6
BK
196 _Safe_sequence_base::
197 _M_detach_singular()
198 {
99827523 199 __gnu_cxx::__scoped_lock sentry(_M_get_mutex());
eebbe2c7 200 for (_Safe_iterator_base* __iter = _M_iterators; __iter;)
4be58168 201 {
f18be892
PC
202 _Safe_iterator_base* __old = __iter;
203 __iter = __iter->_M_next;
204 if (__old->_M_singular())
eebbe2c7 205 __old->_M_detach_single();
4be58168 206 }
285b36d6 207
eebbe2c7 208 for (_Safe_iterator_base* __iter2 = _M_const_iterators; __iter2;)
4be58168 209 {
95b147fe
SM
210 _Safe_iterator_base* __old = __iter2;
211 __iter2 = __iter2->_M_next;
f18be892 212 if (__old->_M_singular())
eebbe2c7 213 __old->_M_detach_single();
4be58168 214 }
285b36d6 215 }
cd07aa11
PC
216
217 void
285b36d6
BK
218 _Safe_sequence_base::
219 _M_revalidate_singular()
220 {
99827523 221 __gnu_cxx::__scoped_lock sentry(_M_get_mutex());
cd07aa11
PC
222 for (_Safe_iterator_base* __iter = _M_iterators; __iter;
223 __iter = __iter->_M_next)
224 __iter->_M_version = _M_version;
225
226 for (_Safe_iterator_base* __iter2 = _M_const_iterators; __iter2;
227 __iter2 = __iter2->_M_next)
228 __iter2->_M_version = _M_version;
285b36d6
BK
229 }
230
eebbe2c7 231 void
285b36d6
BK
232 _Safe_sequence_base::
233 _M_swap(_Safe_sequence_base& __x)
234 {
afe96d41
FD
235 // We need to lock both sequences to swap
236 using namespace __gnu_cxx;
237 __mutex *__this_mutex = &_M_get_mutex();
238 __mutex *__x_mutex = &__x._M_get_mutex();
239 if (__this_mutex == __x_mutex)
240 {
241 __scoped_lock __lock(*__this_mutex);
242 swap_seq(*this, __x);
243 }
244 else
245 {
246 __scoped_lock __l1(__this_mutex < __x_mutex
247 ? *__this_mutex : *__x_mutex);
248 __scoped_lock __l2(__this_mutex < __x_mutex
249 ? *__x_mutex : *__this_mutex);
250 swap_seq(*this, __x);
251 }
285b36d6 252 }
eebbe2c7
PC
253
254 __gnu_cxx::__mutex&
255 _Safe_sequence_base::
5d51b87a 256 _M_get_mutex() throw ()
afe96d41
FD
257 { return get_safe_base_mutex(this); }
258
259 void
260 _Safe_sequence_base::
261 _M_attach(_Safe_iterator_base* __it, bool __constant)
262 {
263 __gnu_cxx::__scoped_lock sentry(_M_get_mutex());
264 _M_attach_single(__it, __constant);
265 }
266
267 void
268 _Safe_sequence_base::
269 _M_attach_single(_Safe_iterator_base* __it, bool __constant) throw ()
270 {
271 _Safe_iterator_base*& __its =
272 __constant ? _M_const_iterators : _M_iterators;
273 __it->_M_next = __its;
274 if (__it->_M_next)
275 __it->_M_next->_M_prior = __it;
276 __its = __it;
277 }
278
279 void
280 _Safe_sequence_base::
281 _M_detach(_Safe_iterator_base* __it)
282 {
283 // Remove __it from this sequence's list
284 __gnu_cxx::__scoped_lock sentry(_M_get_mutex());
285 _M_detach_single(__it);
286 }
287
288 void
289 _Safe_sequence_base::
290 _M_detach_single(_Safe_iterator_base* __it) throw ()
291 {
292 // Remove __it from this sequence's list
8c9f4dfa 293 __it->_M_unlink();
afe96d41
FD
294 if (_M_const_iterators == __it)
295 _M_const_iterators = __it->_M_next;
296 if (_M_iterators == __it)
297 _M_iterators = __it->_M_next;
298 }
eebbe2c7
PC
299
300 void
285b36d6
BK
301 _Safe_iterator_base::
302 _M_attach(_Safe_sequence_base* __seq, bool __constant)
303 {
afe96d41
FD
304 _M_detach();
305
306 // Attach to the new sequence (if there is one)
307 if (__seq)
308 {
309 _M_sequence = __seq;
310 _M_version = _M_sequence->_M_version;
311 _M_sequence->_M_attach(this, __constant);
312 }
eebbe2c7
PC
313 }
314
315 void
316 _Safe_iterator_base::
5d51b87a 317 _M_attach_single(_Safe_sequence_base* __seq, bool __constant) throw ()
eebbe2c7
PC
318 {
319 _M_detach_single();
285b36d6
BK
320
321 // Attach to the new sequence (if there is one)
322 if (__seq)
285b36d6 323 {
4be58168
BK
324 _M_sequence = __seq;
325 _M_version = _M_sequence->_M_version;
afe96d41 326 _M_sequence->_M_attach_single(this, __constant);
285b36d6 327 }
285b36d6
BK
328 }
329
eebbe2c7 330 void
285b36d6
BK
331 _Safe_iterator_base::
332 _M_detach()
333 {
afe96d41 334 if (_M_sequence)
77e0bf4e 335 _M_sequence->_M_detach(this);
afe96d41
FD
336
337 _M_reset();
eebbe2c7
PC
338 }
339
340 void
341 _Safe_iterator_base::
5d51b87a 342 _M_detach_single() throw ()
eebbe2c7 343 {
285b36d6 344 if (_M_sequence)
77e0bf4e 345 _M_sequence->_M_detach_single(this);
285b36d6 346
afe96d41
FD
347 _M_reset();
348 }
349
350 void
351 _Safe_iterator_base::
352 _M_reset() throw ()
353 {
285b36d6
BK
354 _M_sequence = 0;
355 _M_version = 0;
356 _M_prior = 0;
357 _M_next = 0;
358 }
eebbe2c7 359
285b36d6
BK
360 bool
361 _Safe_iterator_base::
5d51b87a 362 _M_singular() const throw ()
285b36d6
BK
363 { return !_M_sequence || _M_version != _M_sequence->_M_version; }
364
365 bool
366 _Safe_iterator_base::
5d51b87a 367 _M_can_compare(const _Safe_iterator_base& __x) const throw ()
285b36d6 368 {
3cbc7af0
BK
369 return (!_M_singular()
370 && !__x._M_singular() && _M_sequence == __x._M_sequence);
285b36d6
BK
371 }
372
eebbe2c7
PC
373 __gnu_cxx::__mutex&
374 _Safe_iterator_base::
5d51b87a 375 _M_get_mutex() throw ()
afe96d41 376 { return get_safe_base_mutex(_M_sequence); }
eebbe2c7 377
364c862b 378 _Safe_unordered_container_base*
77e0bf4e 379 _Safe_local_iterator_base::
364c862b
FD
380 _M_get_container() const _GLIBCXX_NOEXCEPT
381 { return static_cast<_Safe_unordered_container_base*>(_M_sequence); }
77e0bf4e
FD
382
383 void
384 _Safe_local_iterator_base::
364c862b 385 _M_attach(_Safe_sequence_base* __cont, bool __constant)
77e0bf4e
FD
386 {
387 _M_detach();
388
364c862b
FD
389 // Attach to the new container (if there is one)
390 if (__cont)
77e0bf4e 391 {
364c862b 392 _M_sequence = __cont;
77e0bf4e 393 _M_version = _M_sequence->_M_version;
364c862b 394 _M_get_container()->_M_attach_local(this, __constant);
77e0bf4e
FD
395 }
396 }
397
398 void
399 _Safe_local_iterator_base::
364c862b 400 _M_attach_single(_Safe_sequence_base* __cont, bool __constant) throw ()
77e0bf4e
FD
401 {
402 _M_detach_single();
403
364c862b
FD
404 // Attach to the new container (if there is one)
405 if (__cont)
77e0bf4e 406 {
364c862b 407 _M_sequence = __cont;
77e0bf4e 408 _M_version = _M_sequence->_M_version;
364c862b 409 _M_get_container()->_M_attach_local_single(this, __constant);
77e0bf4e
FD
410 }
411 }
412
413 void
414 _Safe_local_iterator_base::
415 _M_detach()
416 {
417 if (_M_sequence)
364c862b 418 _M_get_container()->_M_detach_local(this);
77e0bf4e
FD
419
420 _M_reset();
421 }
422
423 void
424 _Safe_local_iterator_base::
425 _M_detach_single() throw ()
426 {
427 if (_M_sequence)
364c862b 428 _M_get_container()->_M_detach_local_single(this);
77e0bf4e
FD
429
430 _M_reset();
431 }
432
433 void
364c862b 434 _Safe_unordered_container_base::
77e0bf4e
FD
435 _M_detach_all()
436 {
437 __gnu_cxx::__scoped_lock sentry(_M_get_mutex());
438 detach_all(_M_iterators);
439 _M_iterators = 0;
440
441 detach_all(_M_const_iterators);
442 _M_const_iterators = 0;
443
444 detach_all(_M_local_iterators);
445 _M_local_iterators = 0;
446
447 detach_all(_M_const_local_iterators);
448 _M_const_local_iterators = 0;
449 }
450
451 void
364c862b
FD
452 _Safe_unordered_container_base::
453 _M_swap(_Safe_unordered_container_base& __x)
77e0bf4e 454 {
364c862b 455 // We need to lock both containers to swap
77e0bf4e
FD
456 using namespace __gnu_cxx;
457 __mutex *__this_mutex = &_M_get_mutex();
458 __mutex *__x_mutex = &__x._M_get_mutex();
459 if (__this_mutex == __x_mutex)
460 {
461 __scoped_lock __lock(*__this_mutex);
364c862b 462 swap_ucont(*this, __x);
77e0bf4e
FD
463 }
464 else
465 {
466 __scoped_lock __l1(__this_mutex < __x_mutex
467 ? *__this_mutex : *__x_mutex);
468 __scoped_lock __l2(__this_mutex < __x_mutex
469 ? *__x_mutex : *__this_mutex);
364c862b 470 swap_ucont(*this, __x);
77e0bf4e
FD
471 }
472 }
473
474 void
364c862b 475 _Safe_unordered_container_base::
77e0bf4e
FD
476 _M_attach_local(_Safe_iterator_base* __it, bool __constant)
477 {
478 __gnu_cxx::__scoped_lock sentry(_M_get_mutex());
479 _M_attach_local_single(__it, __constant);
480 }
481
482 void
364c862b 483 _Safe_unordered_container_base::
77e0bf4e
FD
484 _M_attach_local_single(_Safe_iterator_base* __it, bool __constant) throw ()
485 {
486 _Safe_iterator_base*& __its =
487 __constant ? _M_const_local_iterators : _M_local_iterators;
488 __it->_M_next = __its;
489 if (__it->_M_next)
490 __it->_M_next->_M_prior = __it;
491 __its = __it;
492 }
493
494 void
364c862b 495 _Safe_unordered_container_base::
77e0bf4e
FD
496 _M_detach_local(_Safe_iterator_base* __it)
497 {
364c862b 498 // Remove __it from this container's list
77e0bf4e
FD
499 __gnu_cxx::__scoped_lock sentry(_M_get_mutex());
500 _M_detach_local_single(__it);
501 }
502
503 void
364c862b 504 _Safe_unordered_container_base::
77e0bf4e
FD
505 _M_detach_local_single(_Safe_iterator_base* __it) throw ()
506 {
364c862b 507 // Remove __it from this container's list
77e0bf4e
FD
508 __it->_M_unlink();
509 if (_M_const_local_iterators == __it)
510 _M_const_local_iterators = __it->_M_next;
511 if (_M_local_iterators == __it)
512 _M_local_iterators = __it->_M_next;
513 }
514
285b36d6
BK
515 void
516 _Error_formatter::_Parameter::
4be58168 517 _M_print_field(const _Error_formatter* __formatter, const char* __name) const
285b36d6
BK
518 {
519 assert(this->_M_kind != _Parameter::__unused_param);
f18be892
PC
520 const int __bufsize = 64;
521 char __buf[__bufsize];
285b36d6
BK
522
523 if (_M_kind == __iterator)
285b36d6 524 {
4be58168
BK
525 if (strcmp(__name, "name") == 0)
526 {
527 assert(_M_variant._M_iterator._M_name);
528 __formatter->_M_print_word(_M_variant._M_iterator._M_name);
529 }
530 else if (strcmp(__name, "address") == 0)
531 {
f18be892 532 __formatter->_M_format_word(__buf, __bufsize, "%p",
4be58168 533 _M_variant._M_iterator._M_address);
f18be892 534 __formatter->_M_print_word(__buf);
4be58168
BK
535 }
536 else if (strcmp(__name, "type") == 0)
537 {
0f136367
PC
538 if (!_M_variant._M_iterator._M_type)
539 __formatter->_M_print_word("<unknown type>");
540 else
541 // TBD: demangle!
542 __formatter->_M_print_word(_M_variant._M_iterator.
543 _M_type->name());
4be58168
BK
544 }
545 else if (strcmp(__name, "constness") == 0)
546 {
547 static const char* __constness_names[__last_constness] =
548 {
549 "<unknown>",
550 "constant",
551 "mutable"
552 };
0f136367
PC
553 __formatter->_M_print_word(__constness_names[_M_variant.
554 _M_iterator.
555 _M_constness]);
4be58168
BK
556 }
557 else if (strcmp(__name, "state") == 0)
558 {
559 static const char* __state_names[__last_state] =
560 {
561 "<unknown>",
562 "singular",
563 "dereferenceable (start-of-sequence)",
564 "dereferenceable",
b8b4301e 565 "past-the-end",
68478bb4 566 "before-begin"
4be58168 567 };
0f136367
PC
568 __formatter->_M_print_word(__state_names[_M_variant.
569 _M_iterator._M_state]);
4be58168
BK
570 }
571 else if (strcmp(__name, "sequence") == 0)
572 {
573 assert(_M_variant._M_iterator._M_sequence);
f18be892 574 __formatter->_M_format_word(__buf, __bufsize, "%p",
4be58168 575 _M_variant._M_iterator._M_sequence);
f18be892 576 __formatter->_M_print_word(__buf);
4be58168
BK
577 }
578 else if (strcmp(__name, "seq_type") == 0)
579 {
0f136367
PC
580 if (!_M_variant._M_iterator._M_seq_type)
581 __formatter->_M_print_word("<unknown seq_type>");
582 else
583 // TBD: demangle!
584 __formatter->_M_print_word(_M_variant._M_iterator.
585 _M_seq_type->name());
4be58168
BK
586 }
587 else
588 assert(false);
285b36d6 589 }
285b36d6 590 else if (_M_kind == __sequence)
285b36d6 591 {
4be58168
BK
592 if (strcmp(__name, "name") == 0)
593 {
594 assert(_M_variant._M_sequence._M_name);
595 __formatter->_M_print_word(_M_variant._M_sequence._M_name);
596 }
597 else if (strcmp(__name, "address") == 0)
598 {
599 assert(_M_variant._M_sequence._M_address);
f18be892 600 __formatter->_M_format_word(__buf, __bufsize, "%p",
4be58168 601 _M_variant._M_sequence._M_address);
f18be892 602 __formatter->_M_print_word(__buf);
4be58168
BK
603 }
604 else if (strcmp(__name, "type") == 0)
605 {
0f136367
PC
606 if (!_M_variant._M_sequence._M_type)
607 __formatter->_M_print_word("<unknown type>");
608 else
609 // TBD: demangle!
610 __formatter->_M_print_word(_M_variant._M_sequence.
611 _M_type->name());
4be58168
BK
612 }
613 else
614 assert(false);
285b36d6 615 }
285b36d6 616 else if (_M_kind == __integer)
285b36d6 617 {
4be58168
BK
618 if (strcmp(__name, "name") == 0)
619 {
620 assert(_M_variant._M_integer._M_name);
621 __formatter->_M_print_word(_M_variant._M_integer._M_name);
622 }
623 else
285b36d6 624 assert(false);
4be58168 625 }
285b36d6 626 else if (_M_kind == __string)
285b36d6 627 {
4be58168
BK
628 if (strcmp(__name, "name") == 0)
629 {
630 assert(_M_variant._M_string._M_name);
631 __formatter->_M_print_word(_M_variant._M_string._M_name);
632 }
633 else
634 assert(false);
285b36d6 635 }
285b36d6 636 else
4be58168
BK
637 {
638 assert(false);
639 }
285b36d6 640 }
4be58168 641
285b36d6
BK
642 void
643 _Error_formatter::_Parameter::
644 _M_print_description(const _Error_formatter* __formatter) const
645 {
f18be892
PC
646 const int __bufsize = 128;
647 char __buf[__bufsize];
285b36d6
BK
648
649 if (_M_kind == __iterator)
285b36d6 650 {
4be58168
BK
651 __formatter->_M_print_word("iterator ");
652 if (_M_variant._M_iterator._M_name)
653 {
f18be892 654 __formatter->_M_format_word(__buf, __bufsize, "\"%s\" ",
4be58168 655 _M_variant._M_iterator._M_name);
f18be892 656 __formatter->_M_print_word(__buf);
4be58168
BK
657 }
658
f18be892 659 __formatter->_M_format_word(__buf, __bufsize, "@ 0x%p {\n",
4be58168 660 _M_variant._M_iterator._M_address);
f18be892 661 __formatter->_M_print_word(__buf);
4be58168
BK
662 if (_M_variant._M_iterator._M_type)
663 {
664 __formatter->_M_print_word("type = ");
665 _M_print_field(__formatter, "type");
666
667 if (_M_variant._M_iterator._M_constness != __unknown_constness)
668 {
669 __formatter->_M_print_word(" (");
670 _M_print_field(__formatter, "constness");
671 __formatter->_M_print_word(" iterator)");
672 }
673 __formatter->_M_print_word(";\n");
674 }
285b36d6 675
4be58168
BK
676 if (_M_variant._M_iterator._M_state != __unknown_state)
677 {
678 __formatter->_M_print_word(" state = ");
679 _M_print_field(__formatter, "state");
680 __formatter->_M_print_word(";\n");
681 }
285b36d6 682
4be58168
BK
683 if (_M_variant._M_iterator._M_sequence)
684 {
685 __formatter->_M_print_word(" references sequence ");
686 if (_M_variant._M_iterator._M_seq_type)
687 {
688 __formatter->_M_print_word("with type `");
689 _M_print_field(__formatter, "seq_type");
690 __formatter->_M_print_word("' ");
691 }
692
f18be892 693 __formatter->_M_format_word(__buf, __bufsize, "@ 0x%p\n",
4be58168 694 _M_variant._M_sequence._M_address);
f18be892 695 __formatter->_M_print_word(__buf);
4be58168
BK
696 }
697 __formatter->_M_print_word("}\n");
285b36d6 698 }
285b36d6 699 else if (_M_kind == __sequence)
285b36d6 700 {
4be58168
BK
701 __formatter->_M_print_word("sequence ");
702 if (_M_variant._M_sequence._M_name)
703 {
f18be892 704 __formatter->_M_format_word(__buf, __bufsize, "\"%s\" ",
4be58168 705 _M_variant._M_sequence._M_name);
f18be892 706 __formatter->_M_print_word(__buf);
4be58168
BK
707 }
708
f18be892 709 __formatter->_M_format_word(__buf, __bufsize, "@ 0x%p {\n",
4be58168 710 _M_variant._M_sequence._M_address);
f18be892 711 __formatter->_M_print_word(__buf);
4be58168
BK
712
713 if (_M_variant._M_sequence._M_type)
714 {
715 __formatter->_M_print_word(" type = ");
716 _M_print_field(__formatter, "type");
717 __formatter->_M_print_word(";\n");
718 }
719 __formatter->_M_print_word("}\n");
285b36d6 720 }
285b36d6
BK
721 }
722
723 const _Error_formatter&
5d51b87a 724 _Error_formatter::_M_message(_Debug_msg_id __id) const throw ()
285b36d6
BK
725 { return this->_M_message(_S_debug_messages[__id]); }
726
727 void
728 _Error_formatter::_M_error() const
729 {
f18be892
PC
730 const int __bufsize = 128;
731 char __buf[__bufsize];
285b36d6
BK
732
733 // Emit file & line number information
734 _M_column = 1;
735 _M_wordwrap = false;
736 if (_M_file)
4be58168 737 {
f18be892
PC
738 _M_format_word(__buf, __bufsize, "%s:", _M_file);
739 _M_print_word(__buf);
740 _M_column += strlen(__buf);
4be58168 741 }
285b36d6
BK
742
743 if (_M_line > 0)
4be58168 744 {
f18be892
PC
745 _M_format_word(__buf, __bufsize, "%u:", _M_line);
746 _M_print_word(__buf);
747 _M_column += strlen(__buf);
4be58168 748 }
285b36d6 749
5dddb7e5
PC
750 if (_M_max_length)
751 _M_wordwrap = true;
285b36d6
BK
752 _M_print_word("error: ");
753
754 // Print the error message
755 assert(_M_text);
756 _M_print_string(_M_text);
757 _M_print_word(".\n");
758
759 // Emit descriptions of the objects involved in the operation
760 _M_wordwrap = false;
f18be892
PC
761 bool __has_noninteger_parameters = false;
762 for (unsigned int __i = 0; __i < _M_num_parameters; ++__i)
285b36d6 763 {
f18be892
PC
764 if (_M_parameters[__i]._M_kind == _Parameter::__iterator
765 || _M_parameters[__i]._M_kind == _Parameter::__sequence)
4be58168 766 {
f18be892 767 if (!__has_noninteger_parameters)
4be58168
BK
768 {
769 _M_first_line = true;
770 _M_print_word("\nObjects involved in the operation:\n");
f18be892 771 __has_noninteger_parameters = true;
4be58168 772 }
f18be892 773 _M_parameters[__i]._M_print_description(this);
4be58168 774 }
285b36d6 775 }
285b36d6
BK
776
777 abort();
778 }
779
9dc420e6 780 template<typename _Tp>
4be58168
BK
781 void
782 _Error_formatter::_M_format_word(char* __buf,
347669a0 783 int __n __attribute__ ((__unused__)),
5d51b87a 784 const char* __fmt, _Tp __s) const throw ()
4be58168
BK
785 {
786#ifdef _GLIBCXX_USE_C99
787 std::snprintf(__buf, __n, __fmt, __s);
788#else
789 std::sprintf(__buf, __fmt, __s);
790#endif
791 }
792
793
285b36d6
BK
794 void
795 _Error_formatter::_M_print_word(const char* __word) const
796 {
797 if (!_M_wordwrap)
4be58168
BK
798 {
799 fprintf(stderr, "%s", __word);
800 return;
801 }
285b36d6
BK
802
803 size_t __length = strlen(__word);
804 if (__length == 0)
805 return;
806
807 if ((_M_column + __length < _M_max_length)
808 || (__length >= _M_max_length && _M_column == 1))
285b36d6 809 {
4be58168
BK
810 // If this isn't the first line, indent
811 if (_M_column == 1 && !_M_first_line)
812 {
f18be892 813 char __spacing[_M_indent + 1];
4be58168 814 for (int i = 0; i < _M_indent; ++i)
f18be892
PC
815 __spacing[i] = ' ';
816 __spacing[_M_indent] = '\0';
817 fprintf(stderr, "%s", __spacing);
4be58168
BK
818 _M_column += _M_indent;
819 }
820
821 fprintf(stderr, "%s", __word);
822 _M_column += __length;
823
824 if (__word[__length - 1] == '\n')
825 {
826 _M_first_line = false;
827 _M_column = 1;
828 }
285b36d6 829 }
4be58168 830 else
285b36d6 831 {
285b36d6 832 _M_column = 1;
4be58168
BK
833 _M_print_word("\n");
834 _M_print_word(__word);
285b36d6 835 }
285b36d6
BK
836 }
837
838 void
839 _Error_formatter::
840 _M_print_string(const char* __string) const
841 {
842 const char* __start = __string;
1ab79481 843 const char* __finish = __start;
f18be892
PC
844 const int __bufsize = 128;
845 char __buf[__bufsize];
285b36d6
BK
846
847 while (*__start)
285b36d6 848 {
4be58168
BK
849 if (*__start != '%')
850 {
1ab79481
BK
851 // [__start, __finish) denotes the next word
852 __finish = __start;
853 while (isalnum(*__finish))
854 ++__finish;
855 if (__start == __finish)
856 ++__finish;
857 if (isspace(*__finish))
858 ++__finish;
4be58168 859
1ab79481 860 const ptrdiff_t __len = __finish - __start;
8844a2f5 861 assert(__len < __bufsize);
b13de673 862 memcpy(__buf, __start, __len);
8844a2f5 863 __buf[__len] = '\0';
f18be892 864 _M_print_word(__buf);
1ab79481 865 __start = __finish;
4be58168
BK
866
867 // Skip extra whitespace
868 while (*__start == ' ')
869 ++__start;
870
871 continue;
872 }
285b36d6 873
285b36d6 874 ++__start;
285b36d6 875 assert(*__start);
33d4e9b2
PC
876 if (*__start == '%')
877 {
878 _M_print_word("%");
879 ++__start;
880 continue;
881 }
882
883 // Get the parameter number
884 assert(*__start >= '1' && *__start <= '9');
f18be892
PC
885 size_t __param = *__start - '0';
886 --__param;
887 assert(__param < _M_num_parameters);
285b36d6 888
33d4e9b2
PC
889 // '.' separates the parameter number from the field
890 // name, if there is one.
891 ++__start;
892 if (*__start != '.')
893 {
894 assert(*__start == ';');
895 ++__start;
f18be892
PC
896 __buf[0] = '\0';
897 if (_M_parameters[__param]._M_kind == _Parameter::__integer)
33d4e9b2 898 {
f18be892
PC
899 _M_format_word(__buf, __bufsize, "%ld",
900 _M_parameters[__param]._M_variant._M_integer._M_value);
901 _M_print_word(__buf);
33d4e9b2 902 }
f18be892
PC
903 else if (_M_parameters[__param]._M_kind == _Parameter::__string)
904 _M_print_string(_M_parameters[__param]._M_variant._M_string._M_value);
33d4e9b2
PC
905 continue;
906 }
907
908 // Extract the field name we want
f18be892
PC
909 enum { __max_field_len = 16 };
910 char __field[__max_field_len];
911 int __field_idx = 0;
33d4e9b2
PC
912 ++__start;
913 while (*__start != ';')
914 {
915 assert(*__start);
f18be892
PC
916 assert(__field_idx < __max_field_len-1);
917 __field[__field_idx++] = *__start++;
33d4e9b2
PC
918 }
919 ++__start;
f18be892 920 __field[__field_idx] = 0;
33d4e9b2 921
f18be892 922 _M_parameters[__param]._M_print_field(this, __field);
33d4e9b2 923 }
285b36d6 924 }
4be58168 925
5dddb7e5 926 void
5d51b87a 927 _Error_formatter::_M_get_max_length() const throw ()
5dddb7e5
PC
928 {
929 const char* __nptr = std::getenv("GLIBCXX_DEBUG_MESSAGE_LENGTH");
930 if (__nptr)
931 {
932 char* __endptr;
933 const unsigned long __ret = std::strtoul(__nptr, &__endptr, 0);
934 if (*__nptr != '\0' && *__endptr == '\0')
935 _M_max_length = __ret;
936 }
937 }
938
4be58168
BK
939 // Instantiations.
940 template
941 void
347669a0
BK
942 _Error_formatter::_M_format_word(char*, int, const char*,
943 const void*) const;
4be58168
BK
944
945 template
946 void
347669a0 947 _Error_formatter::_M_format_word(char*, int, const char*, long) const;
4be58168
BK
948
949 template
950 void
347669a0
BK
951 _Error_formatter::_M_format_word(char*, int, const char*,
952 std::size_t) const;
4be58168
BK
953
954 template
955 void
347669a0
BK
956 _Error_formatter::_M_format_word(char*, int, const char*,
957 const char*) const;
285b36d6 958} // namespace __gnu_debug