1 // Debugging support -*- C++ -*- 2 3 // Copyright (C) 2013-2014 Free Software Foundation, Inc. 4 // 5 // This file is part of GCC. 6 // 7 // GCC is free software; you can redistribute it and/or modify 8 // it under the terms of the GNU General Public License as published by 9 // the Free Software Foundation; either version 3, or (at your option) 10 // any later version. 11 // 12 // GCC 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 // 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. 20 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/>. 25 26 #include <stdarg.h> 27 #include <bits/functexcept.h> 28 #include <bits/locale_facets.h> 29 30 namespace std { 31 _GLIBCXX_BEGIN_NAMESPACE_VERSION 32 template<typename _CharT, typename _ValueT> 33 int 34 __int_to_char(_CharT* __bufend, _ValueT __v, const _CharT* __lit, 35 ios_base::fmtflags __flags, bool __dec); 36 _GLIBCXX_END_NAMESPACE_VERSION 37 } 38 39 namespace __gnu_cxx { 40 41 // Private helper to throw logic error if snprintf_lite runs out 42 // of space (which is not expected to ever happen). 43 // NUL-terminates __buf. 44 void 45 __throw_insufficient_space(const char *__buf, const char *__bufend) 46 __attribute__((__noreturn__)); 47 48 void __throw_insufficient_space(const char * __buf,const char * __bufend)49 __throw_insufficient_space(const char *__buf, const char *__bufend) 50 { 51 // Include space for trailing NUL. 52 const size_t __len = __bufend - __buf + 1; 53 54 const char __err[] = "not enough space for format expansion " 55 "(Please submit full bug report at http://gcc.gnu.org/bugs.html):\n "; 56 const size_t __errlen = sizeof(__err) - 1; 57 58 char *const __e 59 = static_cast<char*>(__builtin_alloca(__errlen + __len)); 60 61 __builtin_memcpy(__e, __err, __errlen); 62 __builtin_memcpy(__e + __errlen, __buf, __len - 1); 63 __e[__errlen + __len - 1] = '\0'; 64 std::__throw_logic_error(__e); 65 } 66 67 68 // Private routine to append decimal representation of VAL to the given 69 // BUFFER, but not more than BUFSIZE characters. 70 // Does not NUL-terminate the output buffer. 71 // Returns number of characters appended, or -1 if BUFSIZE is too small. __concat_size_t(char * __buf,size_t __bufsize,size_t __val)72 int __concat_size_t(char *__buf, size_t __bufsize, size_t __val) 73 { 74 // __int_to_char is explicitly instantiated and available only for 75 // some, but not all, types. See locale-inst.cc. 76 #ifdef _GLIBCXX_USE_LONG_LONG 77 unsigned long long __val2 = __val; 78 #else 79 unsigned long __val2 = __val; 80 #endif 81 // Long enough for decimal representation. 82 int __ilen = 3 * sizeof(__val2); 83 char *__cs = static_cast<char*>(__builtin_alloca(__ilen)); 84 size_t __len = std::__int_to_char(__cs + __ilen, __val2, 85 std::__num_base::_S_atoms_out, 86 std::ios_base::dec, true); 87 if (__bufsize < __len) 88 return -1; 89 90 __builtin_memcpy(__buf, __cs + __ilen - __len, __len); 91 return __len; 92 } 93 94 95 // Private routine to print into __buf arguments according to format, 96 // not to exceed __bufsize. 97 // Only '%%', '%s' and '%zu' format specifiers are understood. 98 // Returns number of characters printed (excluding terminating NUL). 99 // Always NUL-terminates __buf. 100 // Throws logic_error on insufficient space. __snprintf_lite(char * __buf,size_t __bufsize,const char * __fmt,va_list __ap)101 int __snprintf_lite(char *__buf, size_t __bufsize, const char *__fmt, 102 va_list __ap) 103 { 104 char *__d = __buf; 105 const char *__s = __fmt; 106 const char *const __limit = __d + __bufsize - 1; // Leave space for NUL. 107 108 while (__s[0] != '\0' && __d < __limit) 109 { 110 if (__s[0] == '%') 111 switch (__s[1]) 112 { 113 default: // Stray '%'. Just print it. 114 break; 115 case '%': // '%%' 116 __s += 1; 117 break; 118 case 's': // '%s'. 119 { 120 const char *__v = va_arg(__ap, const char *); 121 122 while (__v[0] != '\0' && __d < __limit) 123 *__d++ = *__v++; 124 125 if (__v[0] != '\0') 126 // Not enough space for __fmt expansion. 127 __throw_insufficient_space(__buf, __d); 128 129 __s += 2; // Step over %s. 130 continue; 131 } 132 break; 133 case 'z': 134 if (__s[2] == 'u') // '%zu' -- expand next size_t arg. 135 { 136 const int __len = __concat_size_t(__d, __limit - __d, 137 va_arg(__ap, size_t)); 138 if (__len > 0) 139 __d += __len; 140 else 141 // Not enough space for __fmt expansion. 142 __throw_insufficient_space(__buf, __d); 143 144 __s += 3; // Step over %zu 145 continue; 146 } 147 // Stray '%zX'. Just print it. 148 break; 149 } 150 *__d++ = *__s++; 151 } 152 153 if (__s[0] != '\0') 154 // Not enough space for __fmt expansion. 155 __throw_insufficient_space(__buf, __d); 156 157 *__d = '\0'; 158 return __d - __buf; 159 } 160 161 } // __gnu_cxx 162