1/*
2 * Copyright Andrey Semashev 2007 - 2021.
3 * Distributed under the Boost Software License, Version 1.0.
4 * (See accompanying file LICENSE_1_0.txt or copy at
5 * http://www.boost.org/LICENSE_1_0.txt)
6 */
7/*!
8 * \file dump.cpp
9 * \author Andrey Semashev
10 * \date 03.05.2013
11 *
12 * \brief This header is the Boost.Log library implementation, see the library documentation
13 * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
14 */
15
16#include <boost/log/detail/config.hpp>
17#include <ostream>
18#include <boost/cstdint.hpp>
19#include <boost/log/utility/manipulators/dump.hpp>
20#if defined(_MSC_VER) && (defined(BOOST_LOG_USE_SSSE3) || defined(BOOST_LOG_USE_AVX2))
21#include <boost/winapi/dll.hpp>
22#include <intrin.h> // __cpuid
23#endif
24#include <boost/log/detail/header.hpp>
25
26namespace boost {
27
28BOOST_LOG_OPEN_NAMESPACE
29
30namespace aux {
31
32#if defined(BOOST_LOG_USE_SSSE3)
33extern dump_data_char_t dump_data_char_ssse3;
34extern dump_data_wchar_t dump_data_wchar_ssse3;
35#if !defined(BOOST_NO_CXX11_CHAR16_T)
36extern dump_data_char16_t dump_data_char16_ssse3;
37#endif
38#if !defined(BOOST_NO_CXX11_CHAR32_T)
39extern dump_data_char32_t dump_data_char32_ssse3;
40#endif
41extern dump_data_char_t dump_data_char_ssse3_slow_pshufb;
42extern dump_data_wchar_t dump_data_wchar_ssse3_slow_pshufb;
43#if !defined(BOOST_NO_CXX11_CHAR16_T)
44extern dump_data_char16_t dump_data_char16_ssse3_slow_pshufb;
45#endif
46#if !defined(BOOST_NO_CXX11_CHAR32_T)
47extern dump_data_char32_t dump_data_char32_ssse3_slow_pshufb;
48#endif
49#endif
50#if defined(BOOST_LOG_USE_AVX2)
51extern dump_data_char_t dump_data_char_avx2;
52extern dump_data_wchar_t dump_data_wchar_avx2;
53#if !defined(BOOST_NO_CXX11_CHAR16_T)
54extern dump_data_char16_t dump_data_char16_avx2;
55#endif
56#if !defined(BOOST_NO_CXX11_CHAR32_T)
57extern dump_data_char32_t dump_data_char32_avx2;
58#endif
59#endif
60
61enum { stride = 256 };
62
63BOOST_ALIGNMENT(16) extern const char g_hex_char_table[2][16] =
64{
65 { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' },
66 { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }
67};
68
69template< typename CharT >
70void dump_data_generic(const void* data, std::size_t size, std::basic_ostream< CharT >& strm)
71{
72 typedef CharT char_type;
73
74 char_type buf[stride * 3u];
75
76 const char* const char_table = g_hex_char_table[(strm.flags() & std::ios_base::uppercase) != 0];
77 const std::size_t stride_count = size / stride, tail_size = size % stride;
78
79 const uint8_t* p = static_cast< const uint8_t* >(data);
80 char_type* buf_begin = buf + 1u; // skip the first space of the first chunk
81 char_type* buf_end = buf + sizeof(buf) / sizeof(*buf);
82
83 for (std::size_t i = 0; i < stride_count; ++i)
84 {
85 char_type* b = buf;
86 for (unsigned int j = 0; j < stride; ++j, b += 3u, ++p)
87 {
88 uint32_t n = *p;
89 b[0] = static_cast< char_type >(' ');
90 b[1] = static_cast< char_type >(char_table[n >> 4]);
91 b[2] = static_cast< char_type >(char_table[n & 0x0F]);
92 }
93
94 strm.write(buf_begin, buf_end - buf_begin);
95 buf_begin = buf;
96 }
97
98 if (tail_size > 0)
99 {
100 char_type* b = buf;
101 unsigned int i = 0;
102 do
103 {
104 uint32_t n = *p;
105 b[0] = static_cast< char_type >(' ');
106 b[1] = static_cast< char_type >(char_table[n >> 4]);
107 b[2] = static_cast< char_type >(char_table[n & 0x0F]);
108 ++i;
109 ++p;
110 b += 3u;
111 }
112 while (i < tail_size);
113
114 strm.write(buf_begin, b - buf_begin);
115 }
116}
117
118BOOST_LOG_API dump_data_char_t* dump_data_char = &dump_data_generic< char >;
119BOOST_LOG_API dump_data_wchar_t* dump_data_wchar = &dump_data_generic< wchar_t >;
120#if !defined(BOOST_NO_CXX11_CHAR16_T)
121BOOST_LOG_API dump_data_char16_t* dump_data_char16 = &dump_data_generic< char16_t >;
122#endif
123#if !defined(BOOST_NO_CXX11_CHAR32_T)
124BOOST_LOG_API dump_data_char32_t* dump_data_char32 = &dump_data_generic< char32_t >;
125#endif
126
127#if defined(BOOST_LOG_USE_SSSE3) || defined(BOOST_LOG_USE_AVX2)
128
129BOOST_LOG_ANONYMOUS_NAMESPACE {
130
131struct function_pointer_initializer
132{
133 function_pointer_initializer()
134 {
135 // First, let's check for the max supported cpuid function
136 uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;
137 cpuid(eax, ebx, ecx, edx);
138
139 const uint32_t max_cpuid_function = eax;
140 const uint32_t cpu_vendor[3u] = { ebx, edx, ecx };
141 if (max_cpuid_function >= 1)
142 {
143 eax = 1;
144 ebx = ecx = edx = 0;
145 cpuid(eax, ebx, ecx, edx);
146
147 // Check for SSSE3 support
148 if (ecx & (1u << 9))
149 {
150 const uint32_t family = ((eax >> 8) & 0x0000000F) + ((eax >> 20) & 0x000000FF);
151 const uint32_t model = ((eax >> 4) & 0x0000000F) | ((eax >> 12) & 0x000000F0);
152
153 // Check if the CPU has slow pshufb. Some old Intel Atoms prior to Silvermont.
154 if (cpu_vendor[0] == 0x756e6547 && cpu_vendor[1] == 0x49656e69 && cpu_vendor[2] == 0x6c65746e &&
155 family == 6 && (model == 28 || model == 38 || model == 39 || model == 53 || model == 54))
156 {
157 enable_ssse3_slow_pshufb();
158 }
159 else
160 {
161 enable_ssse3();
162 }
163 }
164
165#if defined(BOOST_LOG_USE_AVX2)
166 if (max_cpuid_function >= 7)
167 {
168 // To check for AVX2 availability we also need to verify that OS supports it
169 // Check that OSXSAVE is supported by CPU
170 if (ecx & (1u << 27))
171 {
172 // Check that it is used by the OS
173 bool mmstate = false;
174#if defined(__GNUC__)
175 // Get the XFEATURE_ENABLED_MASK register
176 __asm__ __volatile__
177 (
178 "xgetbv\n\t"
179 : "=a" (eax), "=d" (edx)
180 : "c" (0)
181 );
182 mmstate = (eax & 6u) == 6u;
183#elif defined(BOOST_WINDOWS)
184 // MSVC does not have an intrinsic for xgetbv, we have to query OS
185 boost::winapi::HMODULE_ hKernel32 = boost::winapi::GetModuleHandleW(L"kernel32.dll");
186 if (hKernel32)
187 {
188 typedef uint64_t (BOOST_WINAPI_WINAPI_CC* get_enabled_extended_features_t)(uint64_t);
189 get_enabled_extended_features_t get_enabled_extended_features = (get_enabled_extended_features_t)boost::winapi::get_proc_address(hKernel32, "GetEnabledExtendedFeatures");
190 if (get_enabled_extended_features)
191 {
192 // XSTATE_MASK_LEGACY_SSE | XSTATE_MASK_GSSE == 6
193 mmstate = get_enabled_extended_features(6u) == 6u;
194 }
195 }
196#endif
197
198 if (mmstate)
199 {
200 // Finally, check for AVX2 support in CPU
201 eax = 7;
202 ebx = ecx = edx = 0;
203 cpuid(eax, ebx, ecx, edx);
204
205 if (ebx & (1u << 5))
206 enable_avx2();
207 }
208 }
209 }
210#endif // defined(BOOST_LOG_USE_AVX2)
211 }
212 }
213
214private:
215 static void cpuid(uint32_t& eax, uint32_t& ebx, uint32_t& ecx, uint32_t& edx)
216 {
217#if defined(__GNUC__)
218#if (defined(__i386__) || defined(__VXWORKS__)) && (defined(__PIC__) || defined(__PIE__)) && !(defined(__clang__) || (defined(BOOST_GCC) && BOOST_GCC >= 50100))
219 // Unless the compiler can do it automatically, we have to backup ebx in 32-bit PIC/PIE code because it is reserved by the ABI.
220 // For VxWorks ebx is reserved on 64-bit as well.
221#if defined(__x86_64__)
222 uint64_t rbx = ebx;
223 __asm__ __volatile__
224 (
225 "xchgq %%rbx, %0\n\t"
226 "cpuid\n\t"
227 "xchgq %%rbx, %0\n\t"
228 : "+DS" (rbx), "+a" (eax), "+c" (ecx), "+d" (edx)
229 );
230 ebx = static_cast< uint32_t >(rbx);
231#else // defined(__x86_64__)
232 __asm__ __volatile__
233 (
234 "xchgl %%ebx, %0\n\t"
235 "cpuid\n\t"
236 "xchgl %%ebx, %0\n\t"
237 : "+DS" (ebx), "+a" (eax), "+c" (ecx), "+d" (edx)
238 );
239#endif // defined(__x86_64__)
240#else
241 __asm__ __volatile__
242 (
243 "cpuid\n\t"
244 : "+a" (eax), "+b" (ebx), "+c" (ecx), "+d" (edx)
245 );
246#endif
247#elif defined(_MSC_VER)
248 int regs[4] = {};
249 __cpuid(regs, eax);
250 eax = regs[0];
251 ebx = regs[1];
252 ecx = regs[2];
253 edx = regs[3];
254#else
255#error Boost.Log: Unexpected compiler
256#endif
257 }
258
259 static void enable_ssse3_slow_pshufb()
260 {
261 dump_data_char = &dump_data_char_ssse3_slow_pshufb;
262 dump_data_wchar = &dump_data_wchar_ssse3_slow_pshufb;
263#if !defined(BOOST_NO_CXX11_CHAR16_T)
264 dump_data_char16 = &dump_data_char16_ssse3_slow_pshufb;
265#endif
266#if !defined(BOOST_NO_CXX11_CHAR32_T)
267 dump_data_char32 = &dump_data_char32_ssse3_slow_pshufb;
268#endif
269 }
270
271 static void enable_ssse3()
272 {
273 dump_data_char = &dump_data_char_ssse3;
274 dump_data_wchar = &dump_data_wchar_ssse3;
275#if !defined(BOOST_NO_CXX11_CHAR16_T)
276 dump_data_char16 = &dump_data_char16_ssse3;
277#endif
278#if !defined(BOOST_NO_CXX11_CHAR32_T)
279 dump_data_char32 = &dump_data_char32_ssse3;
280#endif
281 }
282
283#if defined(BOOST_LOG_USE_AVX2)
284 static void enable_avx2()
285 {
286 dump_data_char = &dump_data_char_avx2;
287 dump_data_wchar = &dump_data_wchar_avx2;
288#if !defined(BOOST_NO_CXX11_CHAR16_T)
289 dump_data_char16 = &dump_data_char16_avx2;
290#endif
291#if !defined(BOOST_NO_CXX11_CHAR32_T)
292 dump_data_char32 = &dump_data_char32_avx2;
293#endif
294 }
295#endif // defined(BOOST_LOG_USE_AVX2)
296};
297
298static function_pointer_initializer g_function_pointer_initializer;
299
300} // namespace
301
302#endif // defined(BOOST_LOG_USE_SSSE3) || defined(BOOST_LOG_USE_AVX2)
303
304} // namespace aux
305
306BOOST_LOG_CLOSE_NAMESPACE // namespace log
307
308} // namespace boost
309
310#include <boost/log/detail/footer.hpp>
311

source code of boost/libs/log/src/dump.cpp