1 // Debugging support -*- C++ -*- 2 3 // Copyright (C) 2013-2022 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 <stddef.h> 28 #include <bits/functexcept.h> 29 30 namespace __gnu_cxx { 31 32 // Private helper to throw logic error if snprintf_lite runs out 33 // of space (which is not expected to ever happen). 34 // NUL-terminates __buf. 35 void 36 __throw_insufficient_space(const char *__buf, const char *__bufend) 37 __attribute__((__noreturn__)); 38 39 void __throw_insufficient_space(const char * __buf,const char * __bufend)40 __throw_insufficient_space(const char *__buf, const char *__bufend) 41 { 42 // Include space for trailing NUL. 43 const size_t __len = __bufend - __buf + 1; 44 45 const char __err[] = "not enough space for format expansion " 46 "(Please submit full bug report at https://gcc.gnu.org/bugs/):\n "; 47 const size_t __errlen = sizeof(__err) - 1; 48 49 char *const __e 50 = static_cast<char*>(__builtin_alloca(__errlen + __len)); 51 52 __builtin_memcpy(__e, __err, __errlen); 53 __builtin_memcpy(__e + __errlen, __buf, __len - 1); 54 __e[__errlen + __len - 1] = '\0'; 55 std::__throw_logic_error(__e); 56 } 57 58 59 // Private routine to append decimal representation of VAL to the given 60 // BUFFER, but not more than BUFSIZE characters. 61 // Does not NUL-terminate the output buffer. 62 // Returns number of characters appended, or -1 if BUFSIZE is too small. __concat_size_t(char * __buf,size_t __bufsize,size_t __val)63 int __concat_size_t(char *__buf, size_t __bufsize, size_t __val) 64 { 65 // Long enough for decimal representation. 66 int __ilen = 3 * sizeof(__val); 67 char *__cs = static_cast<char*>(__builtin_alloca(__ilen)); 68 char* __out = __cs + __ilen; 69 do 70 { 71 *--__out = "0123456789"[__val % 10]; 72 __val /= 10; 73 } 74 while (__val != 0); 75 size_t __len = __cs + __ilen - __out; 76 if (__bufsize < __len) 77 return -1; 78 79 __builtin_memcpy(__buf, __cs + __ilen - __len, __len); 80 return __len; 81 } 82 83 84 // Private routine to print into __buf arguments according to format, 85 // not to exceed __bufsize. 86 // Only '%%', '%s' and '%zu' format specifiers are understood. 87 // Returns number of characters printed (excluding terminating NUL). 88 // Always NUL-terminates __buf. 89 // Throws logic_error on insufficient space. __snprintf_lite(char * __buf,size_t __bufsize,const char * __fmt,va_list __ap)90 int __snprintf_lite(char *__buf, size_t __bufsize, const char *__fmt, 91 va_list __ap) 92 { 93 char *__d = __buf; 94 const char *__s = __fmt; 95 const char *const __limit = __d + __bufsize - 1; // Leave space for NUL. 96 97 while (__s[0] != '\0' && __d < __limit) 98 { 99 if (__s[0] == '%') 100 switch (__s[1]) 101 { 102 default: // Stray '%'. Just print it. 103 break; 104 case '%': // '%%' 105 __s += 1; 106 break; 107 case 's': // '%s'. 108 { 109 const char *__v = va_arg(__ap, const char *); 110 111 while (__v[0] != '\0' && __d < __limit) 112 *__d++ = *__v++; 113 114 if (__v[0] != '\0') 115 // Not enough space for __fmt expansion. 116 __throw_insufficient_space(__buf, __d); 117 118 __s += 2; // Step over %s. 119 continue; 120 } 121 break; 122 case 'z': 123 if (__s[2] == 'u') // '%zu' -- expand next size_t arg. 124 { 125 const int __len = __concat_size_t(__d, __limit - __d, 126 va_arg(__ap, size_t)); 127 if (__len > 0) 128 __d += __len; 129 else 130 // Not enough space for __fmt expansion. 131 __throw_insufficient_space(__buf, __d); 132 133 __s += 3; // Step over %zu 134 continue; 135 } 136 // Stray '%zX'. Just print it. 137 break; 138 } 139 *__d++ = *__s++; 140 } 141 142 if (__s[0] != '\0') 143 // Not enough space for __fmt expansion. 144 __throw_insufficient_space(__buf, __d); 145 146 *__d = '\0'; 147 return __d - __buf; 148 } 149 150 } // __gnu_cxx 151