VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/string/strformatrt.cpp@ 62863

Last change on this file since 62863 was 62564, checked in by vboxsync, 9 years ago

IPRT: Mark unused parameters.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 53.5 KB
Line 
1/* $Id: strformatrt.cpp 62564 2016-07-26 14:43:03Z vboxsync $ */
2/** @file
3 * IPRT - IPRT String Formatter Extensions.
4 */
5
6/*
7 * Copyright (C) 2006-2016 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.215389.xyz. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#define LOG_GROUP RTLOGGROUP_STRING
32#include <iprt/string.h>
33#ifndef RT_NO_EXPORT_SYMBOL
34# define RT_NO_EXPORT_SYMBOL /* don't slurp <linux/module.h> which then again
35 slurps arch-specific headers defining symbols */
36#endif
37#include "internal/iprt.h"
38
39#include <iprt/log.h>
40#include <iprt/assert.h>
41#include <iprt/string.h>
42#include <iprt/stdarg.h>
43#ifdef IN_RING3
44# include <iprt/thread.h>
45# include <iprt/err.h>
46#endif
47#include <iprt/ctype.h>
48#include <iprt/time.h>
49#include <iprt/net.h>
50#include <iprt/path.h>
51#include <iprt/asm.h>
52#define STRFORMAT_WITH_X86
53#ifdef STRFORMAT_WITH_X86
54# include <iprt/x86.h>
55#endif
56#include "internal/string.h"
57
58
59/*********************************************************************************************************************************
60* Global Variables *
61*********************************************************************************************************************************/
62static char g_szHexDigits[17] = "0123456789abcdef";
63
64
65/**
66 * Helper that formats a 16-bit hex word in a IPv6 address.
67 *
68 * @returns Length in chars.
69 * @param pszDst The output buffer. Written from the start.
70 * @param uWord The word to format as hex.
71 */
72static size_t rtstrFormatIPv6HexWord(char *pszDst, uint16_t uWord)
73{
74 size_t off;
75 uint16_t cDigits;
76
77 if (uWord & UINT16_C(0xff00))
78 cDigits = uWord & UINT16_C(0xf000) ? 4 : 3;
79 else
80 cDigits = uWord & UINT16_C(0x00f0) ? 2 : 1;
81
82 off = 0;
83 switch (cDigits)
84 {
85 case 4: pszDst[off++] = g_szHexDigits[(uWord >> 12) & 0xf];
86 case 3: pszDst[off++] = g_szHexDigits[(uWord >> 8) & 0xf];
87 case 2: pszDst[off++] = g_szHexDigits[(uWord >> 4) & 0xf];
88 case 1: pszDst[off++] = g_szHexDigits[(uWord >> 0) & 0xf];
89 break;
90 }
91 pszDst[off] = '\0';
92 return off;
93}
94
95
96/**
97 * Helper function to format IPv6 address according to RFC 5952.
98 *
99 * @returns The number of bytes formatted.
100 * @param pfnOutput Pointer to output function.
101 * @param pvArgOutput Argument for the output function.
102 * @param pIpv6Addr IPv6 address
103 */
104static size_t rtstrFormatIPv6(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput, PCRTNETADDRIPV6 pIpv6Addr)
105{
106 size_t cch; /* result */
107 bool fEmbeddedIpv4;
108 size_t cwHexPart;
109 size_t cwLongestZeroRun;
110 size_t iLongestZeroStart;
111 size_t idx;
112 char szHexWord[8];
113
114 Assert(pIpv6Addr != NULL);
115
116 /*
117 * Check for embedded IPv4 address.
118 *
119 * IPv4-compatible - ::11.22.33.44 (obsolete)
120 * IPv4-mapped - ::ffff:11.22.33.44
121 * IPv4-translated - ::ffff:0:11.22.33.44 (RFC 2765)
122 */
123 fEmbeddedIpv4 = false;
124 cwHexPart = RT_ELEMENTS(pIpv6Addr->au16);
125 if ( pIpv6Addr->au64[0] == 0
126 && ( ( pIpv6Addr->au32[2] == 0
127 && pIpv6Addr->au32[3] != 0
128 && pIpv6Addr->au32[3] != RT_H2BE_U32_C(1) )
129 || pIpv6Addr->au32[2] == RT_H2BE_U32_C(0x0000ffff)
130 || pIpv6Addr->au32[2] == RT_H2BE_U32_C(0xffff0000) ) )
131 {
132 fEmbeddedIpv4 = true;
133 cwHexPart -= 2;
134 }
135
136 /*
137 * Find the longest sequences of two or more zero words.
138 */
139 cwLongestZeroRun = 0;
140 iLongestZeroStart = 0;
141 for (idx = 0; idx < cwHexPart; idx++)
142 if (pIpv6Addr->au16[idx] == 0)
143 {
144 size_t iZeroStart = idx;
145 size_t cwZeroRun;
146 do
147 idx++;
148 while (idx < cwHexPart && pIpv6Addr->au16[idx] == 0);
149 cwZeroRun = idx - iZeroStart;
150 if (cwZeroRun > 1 && cwZeroRun > cwLongestZeroRun)
151 {
152 cwLongestZeroRun = cwZeroRun;
153 iLongestZeroStart = iZeroStart;
154 if (cwZeroRun >= cwHexPart - idx)
155 break;
156 }
157 }
158
159 /*
160 * Do the formatting.
161 */
162 cch = 0;
163 if (cwLongestZeroRun == 0)
164 {
165 for (idx = 0; idx < cwHexPart; ++idx)
166 {
167 if (idx > 0)
168 cch += pfnOutput(pvArgOutput, ":", 1);
169 cch += pfnOutput(pvArgOutput, szHexWord, rtstrFormatIPv6HexWord(szHexWord, RT_BE2H_U16(pIpv6Addr->au16[idx])));
170 }
171
172 if (fEmbeddedIpv4)
173 cch += pfnOutput(pvArgOutput, ":", 1);
174 }
175 else
176 {
177 const size_t iLongestZeroEnd = iLongestZeroStart + cwLongestZeroRun;
178
179 if (iLongestZeroStart == 0)
180 cch += pfnOutput(pvArgOutput, ":", 1);
181 else
182 for (idx = 0; idx < iLongestZeroStart; ++idx)
183 {
184 cch += pfnOutput(pvArgOutput, szHexWord, rtstrFormatIPv6HexWord(szHexWord, RT_BE2H_U16(pIpv6Addr->au16[idx])));
185 cch += pfnOutput(pvArgOutput, ":", 1);
186 }
187
188 if (iLongestZeroEnd == cwHexPart)
189 cch += pfnOutput(pvArgOutput, ":", 1);
190 else
191 {
192 for (idx = iLongestZeroEnd; idx < cwHexPart; ++idx)
193 {
194 cch += pfnOutput(pvArgOutput, ":", 1);
195 cch += pfnOutput(pvArgOutput, szHexWord, rtstrFormatIPv6HexWord(szHexWord, RT_BE2H_U16(pIpv6Addr->au16[idx])));
196 }
197
198 if (fEmbeddedIpv4)
199 cch += pfnOutput(pvArgOutput, ":", 1);
200 }
201 }
202
203 if (fEmbeddedIpv4)
204 cch += RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
205 "%u.%u.%u.%u",
206 pIpv6Addr->au8[12],
207 pIpv6Addr->au8[13],
208 pIpv6Addr->au8[14],
209 pIpv6Addr->au8[15]);
210
211 return cch;
212}
213
214
215/**
216 * Callback to format iprt formatting extentions.
217 * See @ref pg_rt_str_format for a reference on the format types.
218 *
219 * @returns The number of bytes formatted.
220 * @param pfnOutput Pointer to output function.
221 * @param pvArgOutput Argument for the output function.
222 * @param ppszFormat Pointer to the format string pointer. Advance this till the char
223 * after the format specifier.
224 * @param pArgs Pointer to the argument list. Use this to fetch the arguments.
225 * @param cchWidth Format Width. -1 if not specified.
226 * @param cchPrecision Format Precision. -1 if not specified.
227 * @param fFlags Flags (RTSTR_NTFS_*).
228 * @param chArgSize The argument size specifier, 'l' or 'L'.
229 */
230DECLHIDDEN(size_t) rtstrFormatRt(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput, const char **ppszFormat, va_list *pArgs,
231 int cchWidth, int cchPrecision, unsigned fFlags, char chArgSize)
232{
233 const char *pszFormatOrg = *ppszFormat;
234 char ch = *(*ppszFormat)++;
235 size_t cch;
236 char szBuf[80];
237
238 if (ch == 'R')
239 {
240 ch = *(*ppszFormat)++;
241 switch (ch)
242 {
243 /*
244 * Groups 1 and 2.
245 */
246 case 'T':
247 case 'G':
248 case 'H':
249 case 'R':
250 case 'C':
251 case 'I':
252 case 'X':
253 case 'U':
254 {
255 /*
256 * Interpret the type.
257 */
258 typedef enum
259 {
260 RTSF_INT,
261 RTSF_INTW,
262 RTSF_BOOL,
263 RTSF_FP16,
264 RTSF_FP32,
265 RTSF_FP64,
266 RTSF_IPV4,
267 RTSF_IPV6,
268 RTSF_MAC,
269 RTSF_NETADDR,
270 RTSF_UUID
271 } RTSF;
272 static const struct
273 {
274 uint8_t cch; /**< the length of the string. */
275 char sz[10]; /**< the part following 'R'. */
276 uint8_t cb; /**< the size of the type. */
277 uint8_t u8Base; /**< the size of the type. */
278 RTSF enmFormat; /**< The way to format it. */
279 uint16_t fFlags; /**< additional RTSTR_F_* flags. */
280 }
281 /** Sorted array of types, looked up using binary search! */
282 s_aTypes[] =
283 {
284#define STRMEM(str) sizeof(str) - 1, str
285 { STRMEM("Ci"), sizeof(RTINT), 10, RTSF_INT, RTSTR_F_VALSIGNED },
286 { STRMEM("Cp"), sizeof(RTCCPHYS), 16, RTSF_INTW, 0 },
287 { STRMEM("Cr"), sizeof(RTCCUINTREG), 16, RTSF_INTW, 0 },
288 { STRMEM("Cu"), sizeof(RTUINT), 10, RTSF_INT, 0 },
289 { STRMEM("Cv"), sizeof(void *), 16, RTSF_INTW, 0 },
290 { STRMEM("Cx"), sizeof(RTUINT), 16, RTSF_INT, 0 },
291 { STRMEM("Gi"), sizeof(RTGCINT), 10, RTSF_INT, RTSTR_F_VALSIGNED },
292 { STRMEM("Gp"), sizeof(RTGCPHYS), 16, RTSF_INTW, 0 },
293 { STRMEM("Gr"), sizeof(RTGCUINTREG), 16, RTSF_INTW, 0 },
294 { STRMEM("Gu"), sizeof(RTGCUINT), 10, RTSF_INT, 0 },
295 { STRMEM("Gv"), sizeof(RTGCPTR), 16, RTSF_INTW, 0 },
296 { STRMEM("Gx"), sizeof(RTGCUINT), 16, RTSF_INT, 0 },
297 { STRMEM("Hi"), sizeof(RTHCINT), 10, RTSF_INT, RTSTR_F_VALSIGNED },
298 { STRMEM("Hp"), sizeof(RTHCPHYS), 16, RTSF_INTW, 0 },
299 { STRMEM("Hr"), sizeof(RTHCUINTREG), 16, RTSF_INTW, 0 },
300 { STRMEM("Hu"), sizeof(RTHCUINT), 10, RTSF_INT, 0 },
301 { STRMEM("Hv"), sizeof(RTHCPTR), 16, RTSF_INTW, 0 },
302 { STRMEM("Hx"), sizeof(RTHCUINT), 16, RTSF_INT, 0 },
303 { STRMEM("I16"), sizeof(int16_t), 10, RTSF_INT, RTSTR_F_VALSIGNED },
304 { STRMEM("I32"), sizeof(int32_t), 10, RTSF_INT, RTSTR_F_VALSIGNED },
305 { STRMEM("I64"), sizeof(int64_t), 10, RTSF_INT, RTSTR_F_VALSIGNED },
306 { STRMEM("I8"), sizeof(int8_t), 10, RTSF_INT, RTSTR_F_VALSIGNED },
307 { STRMEM("Rv"), sizeof(RTRCPTR), 16, RTSF_INTW, 0 },
308 { STRMEM("Tbool"), sizeof(bool), 10, RTSF_BOOL, 0 },
309 { STRMEM("Tfile"), sizeof(RTFILE), 10, RTSF_INT, 0 },
310 { STRMEM("Tfmode"), sizeof(RTFMODE), 16, RTSF_INTW, 0 },
311 { STRMEM("Tfoff"), sizeof(RTFOFF), 10, RTSF_INT, RTSTR_F_VALSIGNED },
312 { STRMEM("Tfp16"), sizeof(RTFAR16), 16, RTSF_FP16, RTSTR_F_ZEROPAD },
313 { STRMEM("Tfp32"), sizeof(RTFAR32), 16, RTSF_FP32, RTSTR_F_ZEROPAD },
314 { STRMEM("Tfp64"), sizeof(RTFAR64), 16, RTSF_FP64, RTSTR_F_ZEROPAD },
315 { STRMEM("Tgid"), sizeof(RTGID), 10, RTSF_INT, RTSTR_F_VALSIGNED },
316 { STRMEM("Tino"), sizeof(RTINODE), 16, RTSF_INTW, 0 },
317 { STRMEM("Tint"), sizeof(RTINT), 10, RTSF_INT, RTSTR_F_VALSIGNED },
318 { STRMEM("Tiop"), sizeof(RTIOPORT), 16, RTSF_INTW, 0 },
319 { STRMEM("Tldrm"), sizeof(RTLDRMOD), 16, RTSF_INTW, 0 },
320 { STRMEM("Tmac"), sizeof(PCRTMAC), 16, RTSF_MAC, 0 },
321 { STRMEM("Tnaddr"), sizeof(PCRTNETADDR), 10, RTSF_NETADDR,0 },
322 { STRMEM("Tnaipv4"), sizeof(RTNETADDRIPV4), 10, RTSF_IPV4, 0 },
323 { STRMEM("Tnaipv6"), sizeof(PCRTNETADDRIPV6),16, RTSF_IPV6, 0 },
324 { STRMEM("Tnthrd"), sizeof(RTNATIVETHREAD), 16, RTSF_INTW, 0 },
325 { STRMEM("Tproc"), sizeof(RTPROCESS), 16, RTSF_INTW, 0 },
326 { STRMEM("Tptr"), sizeof(RTUINTPTR), 16, RTSF_INTW, 0 },
327 { STRMEM("Treg"), sizeof(RTCCUINTREG), 16, RTSF_INTW, 0 },
328 { STRMEM("Tsel"), sizeof(RTSEL), 16, RTSF_INTW, 0 },
329 { STRMEM("Tsem"), sizeof(RTSEMEVENT), 16, RTSF_INTW, 0 },
330 { STRMEM("Tsock"), sizeof(RTSOCKET), 10, RTSF_INT, 0 },
331 { STRMEM("Tthrd"), sizeof(RTTHREAD), 16, RTSF_INTW, 0 },
332 { STRMEM("Tuid"), sizeof(RTUID), 10, RTSF_INT, RTSTR_F_VALSIGNED },
333 { STRMEM("Tuint"), sizeof(RTUINT), 10, RTSF_INT, 0 },
334 { STRMEM("Tunicp"), sizeof(RTUNICP), 16, RTSF_INTW, RTSTR_F_ZEROPAD },
335 { STRMEM("Tutf16"), sizeof(RTUTF16), 16, RTSF_INTW, RTSTR_F_ZEROPAD },
336 { STRMEM("Tuuid"), sizeof(PCRTUUID), 16, RTSF_UUID, 0 },
337 { STRMEM("Txint"), sizeof(RTUINT), 16, RTSF_INT, 0 },
338 { STRMEM("U16"), sizeof(uint16_t), 10, RTSF_INT, 0 },
339 { STRMEM("U32"), sizeof(uint32_t), 10, RTSF_INT, 0 },
340 { STRMEM("U64"), sizeof(uint64_t), 10, RTSF_INT, 0 },
341 { STRMEM("U8"), sizeof(uint8_t), 10, RTSF_INT, 0 },
342 { STRMEM("X16"), sizeof(uint16_t), 16, RTSF_INT, 0 },
343 { STRMEM("X32"), sizeof(uint32_t), 16, RTSF_INT, 0 },
344 { STRMEM("X64"), sizeof(uint64_t), 16, RTSF_INT, 0 },
345 { STRMEM("X8"), sizeof(uint8_t), 16, RTSF_INT, 0 },
346#undef STRMEM
347 };
348 static const char s_szNull[] = "<NULL>";
349
350 const char *pszType = *ppszFormat - 1;
351 int iStart = 0;
352 int iEnd = RT_ELEMENTS(s_aTypes) - 1;
353 int i = RT_ELEMENTS(s_aTypes) / 2;
354
355 union
356 {
357 uint8_t u8;
358 uint16_t u16;
359 uint32_t u32;
360 uint64_t u64;
361 int8_t i8;
362 int16_t i16;
363 int32_t i32;
364 int64_t i64;
365 RTFAR16 fp16;
366 RTFAR32 fp32;
367 RTFAR64 fp64;
368 bool fBool;
369 PCRTMAC pMac;
370 RTNETADDRIPV4 Ipv4Addr;
371 PCRTNETADDRIPV6 pIpv6Addr;
372 PCRTNETADDR pNetAddr;
373 PCRTUUID pUuid;
374 } u;
375
376 AssertMsg(!chArgSize, ("Not argument size '%c' for RT types! '%.10s'\n", chArgSize, pszFormatOrg));
377 RT_NOREF_PV(chArgSize);
378
379 /*
380 * Lookup the type - binary search.
381 */
382 for (;;)
383 {
384 int iDiff = strncmp(pszType, s_aTypes[i].sz, s_aTypes[i].cch);
385 if (!iDiff)
386 break;
387 if (iEnd == iStart)
388 {
389 AssertMsgFailed(("Invalid format type '%.10s'!\n", pszFormatOrg));
390 return 0;
391 }
392 if (iDiff < 0)
393 iEnd = i - 1;
394 else
395 iStart = i + 1;
396 if (iEnd < iStart)
397 {
398 AssertMsgFailed(("Invalid format type '%.10s'!\n", pszFormatOrg));
399 return 0;
400 }
401 i = iStart + (iEnd - iStart) / 2;
402 }
403
404 /*
405 * Advance the format string and merge flags.
406 */
407 *ppszFormat += s_aTypes[i].cch - 1;
408 fFlags |= s_aTypes[i].fFlags;
409
410 /*
411 * Fetch the argument.
412 * It's important that a signed value gets sign-extended up to 64-bit.
413 */
414 RT_ZERO(u);
415 if (fFlags & RTSTR_F_VALSIGNED)
416 {
417 switch (s_aTypes[i].cb)
418 {
419 case sizeof(int8_t):
420 u.i64 = va_arg(*pArgs, /*int8_t*/int);
421 fFlags |= RTSTR_F_8BIT;
422 break;
423 case sizeof(int16_t):
424 u.i64 = va_arg(*pArgs, /*int16_t*/int);
425 fFlags |= RTSTR_F_16BIT;
426 break;
427 case sizeof(int32_t):
428 u.i64 = va_arg(*pArgs, int32_t);
429 fFlags |= RTSTR_F_32BIT;
430 break;
431 case sizeof(int64_t):
432 u.i64 = va_arg(*pArgs, int64_t);
433 fFlags |= RTSTR_F_64BIT;
434 break;
435 default:
436 AssertMsgFailed(("Invalid format error, size %d'!\n", s_aTypes[i].cb));
437 break;
438 }
439 }
440 else
441 {
442 switch (s_aTypes[i].cb)
443 {
444 case sizeof(uint8_t):
445 u.u8 = va_arg(*pArgs, /*uint8_t*/unsigned);
446 fFlags |= RTSTR_F_8BIT;
447 break;
448 case sizeof(uint16_t):
449 u.u16 = va_arg(*pArgs, /*uint16_t*/unsigned);
450 fFlags |= RTSTR_F_16BIT;
451 break;
452 case sizeof(uint32_t):
453 u.u32 = va_arg(*pArgs, uint32_t);
454 fFlags |= RTSTR_F_32BIT;
455 break;
456 case sizeof(uint64_t):
457 u.u64 = va_arg(*pArgs, uint64_t);
458 fFlags |= RTSTR_F_64BIT;
459 break;
460 case sizeof(RTFAR32):
461 u.fp32 = va_arg(*pArgs, RTFAR32);
462 break;
463 case sizeof(RTFAR64):
464 u.fp64 = va_arg(*pArgs, RTFAR64);
465 break;
466 default:
467 AssertMsgFailed(("Invalid format error, size %d'!\n", s_aTypes[i].cb));
468 break;
469 }
470 }
471
472 /*
473 * Format the output.
474 */
475 switch (s_aTypes[i].enmFormat)
476 {
477 case RTSF_INT:
478 {
479 cch = RTStrFormatNumber(szBuf, u.u64, s_aTypes[i].u8Base, cchWidth, cchPrecision, fFlags);
480 break;
481 }
482
483 /* hex which defaults to max width. */
484 case RTSF_INTW:
485 {
486 Assert(s_aTypes[i].u8Base == 16);
487 if (cchWidth < 0)
488 {
489 cchWidth = s_aTypes[i].cb * 2 + (fFlags & RTSTR_F_SPECIAL ? 2 : 0);
490 fFlags |= RTSTR_F_ZEROPAD;
491 }
492 cch = RTStrFormatNumber(szBuf, u.u64, s_aTypes[i].u8Base, cchWidth, cchPrecision, fFlags);
493 break;
494 }
495
496 case RTSF_BOOL:
497 {
498 static const char s_szTrue[] = "true ";
499 static const char s_szFalse[] = "false";
500 if (u.u64 == 1)
501 return pfnOutput(pvArgOutput, s_szTrue, sizeof(s_szTrue) - 1);
502 if (u.u64 == 0)
503 return pfnOutput(pvArgOutput, s_szFalse, sizeof(s_szFalse) - 1);
504 /* invalid boolean value */
505 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "!%lld!", u.u64);
506 }
507
508 case RTSF_FP16:
509 {
510 fFlags &= ~(RTSTR_F_VALSIGNED | RTSTR_F_BIT_MASK | RTSTR_F_WIDTH | RTSTR_F_PRECISION | RTSTR_F_THOUSAND_SEP);
511 cch = RTStrFormatNumber(&szBuf[0], u.fp16.sel, 16, 4, -1, fFlags | RTSTR_F_16BIT);
512 Assert(cch == 4);
513 szBuf[4] = ':';
514 cch = RTStrFormatNumber(&szBuf[5], u.fp16.off, 16, 4, -1, fFlags | RTSTR_F_16BIT);
515 Assert(cch == 4);
516 cch = 4 + 1 + 4;
517 break;
518 }
519 case RTSF_FP32:
520 {
521 fFlags &= ~(RTSTR_F_VALSIGNED | RTSTR_F_BIT_MASK | RTSTR_F_WIDTH | RTSTR_F_PRECISION | RTSTR_F_THOUSAND_SEP);
522 cch = RTStrFormatNumber(&szBuf[0], u.fp32.sel, 16, 4, -1, fFlags | RTSTR_F_16BIT);
523 Assert(cch == 4);
524 szBuf[4] = ':';
525 cch = RTStrFormatNumber(&szBuf[5], u.fp32.off, 16, 8, -1, fFlags | RTSTR_F_32BIT);
526 Assert(cch == 8);
527 cch = 4 + 1 + 8;
528 break;
529 }
530 case RTSF_FP64:
531 {
532 fFlags &= ~(RTSTR_F_VALSIGNED | RTSTR_F_BIT_MASK | RTSTR_F_WIDTH | RTSTR_F_PRECISION | RTSTR_F_THOUSAND_SEP);
533 cch = RTStrFormatNumber(&szBuf[0], u.fp64.sel, 16, 4, -1, fFlags | RTSTR_F_16BIT);
534 Assert(cch == 4);
535 szBuf[4] = ':';
536 cch = RTStrFormatNumber(&szBuf[5], u.fp64.off, 16, 16, -1, fFlags | RTSTR_F_64BIT);
537 Assert(cch == 16);
538 cch = 4 + 1 + 16;
539 break;
540 }
541
542 case RTSF_IPV4:
543 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
544 "%u.%u.%u.%u",
545 u.Ipv4Addr.au8[0],
546 u.Ipv4Addr.au8[1],
547 u.Ipv4Addr.au8[2],
548 u.Ipv4Addr.au8[3]);
549
550 case RTSF_IPV6:
551 {
552 if (VALID_PTR(u.pIpv6Addr))
553 return rtstrFormatIPv6(pfnOutput, pvArgOutput, u.pIpv6Addr);
554 return pfnOutput(pvArgOutput, s_szNull, sizeof(s_szNull) - 1);
555 }
556
557 case RTSF_MAC:
558 {
559 if (VALID_PTR(u.pMac))
560 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
561 "%02x:%02x:%02x:%02x:%02x:%02x",
562 u.pMac->au8[0],
563 u.pMac->au8[1],
564 u.pMac->au8[2],
565 u.pMac->au8[3],
566 u.pMac->au8[4],
567 u.pMac->au8[5]);
568 return pfnOutput(pvArgOutput, s_szNull, sizeof(s_szNull) - 1);
569 }
570
571 case RTSF_NETADDR:
572 {
573 if (VALID_PTR(u.pNetAddr))
574 {
575 switch (u.pNetAddr->enmType)
576 {
577 case RTNETADDRTYPE_IPV4:
578 if (u.pNetAddr->uPort == RTNETADDR_PORT_NA)
579 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
580 "%u.%u.%u.%u",
581 u.pNetAddr->uAddr.IPv4.au8[0],
582 u.pNetAddr->uAddr.IPv4.au8[1],
583 u.pNetAddr->uAddr.IPv4.au8[2],
584 u.pNetAddr->uAddr.IPv4.au8[3]);
585 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
586 "%u.%u.%u.%u:%u",
587 u.pNetAddr->uAddr.IPv4.au8[0],
588 u.pNetAddr->uAddr.IPv4.au8[1],
589 u.pNetAddr->uAddr.IPv4.au8[2],
590 u.pNetAddr->uAddr.IPv4.au8[3],
591 u.pNetAddr->uPort);
592
593 case RTNETADDRTYPE_IPV6:
594 if (u.pNetAddr->uPort == RTNETADDR_PORT_NA)
595 return rtstrFormatIPv6(pfnOutput, pvArgOutput, &u.pNetAddr->uAddr.IPv6);
596
597 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
598 "[%RTnaipv6]:%u",
599 &u.pNetAddr->uAddr.IPv6,
600 u.pNetAddr->uPort);
601
602 case RTNETADDRTYPE_MAC:
603 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
604 "%02x:%02x:%02x:%02x:%02x:%02x",
605 u.pNetAddr->uAddr.Mac.au8[0],
606 u.pNetAddr->uAddr.Mac.au8[1],
607 u.pNetAddr->uAddr.Mac.au8[2],
608 u.pNetAddr->uAddr.Mac.au8[3],
609 u.pNetAddr->uAddr.Mac.au8[4],
610 u.pNetAddr->uAddr.Mac.au8[5]);
611
612 default:
613 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
614 "unsupported-netaddr-type=%u", u.pNetAddr->enmType);
615
616 }
617 }
618 return pfnOutput(pvArgOutput, s_szNull, sizeof(s_szNull) - 1);
619 }
620
621 case RTSF_UUID:
622 {
623 if (VALID_PTR(u.pUuid))
624 {
625 /* cannot call RTUuidToStr because of GC/R0. */
626 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
627 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
628 RT_H2LE_U32(u.pUuid->Gen.u32TimeLow),
629 RT_H2LE_U16(u.pUuid->Gen.u16TimeMid),
630 RT_H2LE_U16(u.pUuid->Gen.u16TimeHiAndVersion),
631 u.pUuid->Gen.u8ClockSeqHiAndReserved,
632 u.pUuid->Gen.u8ClockSeqLow,
633 u.pUuid->Gen.au8Node[0],
634 u.pUuid->Gen.au8Node[1],
635 u.pUuid->Gen.au8Node[2],
636 u.pUuid->Gen.au8Node[3],
637 u.pUuid->Gen.au8Node[4],
638 u.pUuid->Gen.au8Node[5]);
639 }
640 return pfnOutput(pvArgOutput, s_szNull, sizeof(s_szNull) - 1);
641 }
642
643 default:
644 AssertMsgFailed(("Internal error %d\n", s_aTypes[i].enmFormat));
645 return 0;
646 }
647
648 /*
649 * Finally, output the formatted string and return.
650 */
651 return pfnOutput(pvArgOutput, szBuf, cch);
652 }
653
654
655 /* Group 3 */
656
657 /*
658 * Base name printing.
659 */
660 case 'b':
661 {
662 switch (*(*ppszFormat)++)
663 {
664 case 'n':
665 {
666 const char *pszLastSep;
667 const char *psz = pszLastSep = va_arg(*pArgs, const char *);
668 if (!VALID_PTR(psz))
669 return pfnOutput(pvArgOutput, RT_STR_TUPLE("<null>"));
670
671 while ((ch = *psz) != '\0')
672 {
673 if (RTPATH_IS_SEP(ch))
674 {
675 do
676 psz++;
677 while ((ch = *psz) != '\0' && RTPATH_IS_SEP(ch));
678 if (!ch)
679 break;
680 pszLastSep = psz;
681 }
682 psz++;
683 }
684
685 return pfnOutput(pvArgOutput, pszLastSep, psz - pszLastSep);
686 }
687
688 default:
689 AssertMsgFailed(("Invalid status code format type '%.10s'!\n", pszFormatOrg));
690 break;
691 }
692 break;
693 }
694
695
696 /*
697 * Pretty function / method name printing.
698 */
699 case 'f':
700 {
701 switch (*(*ppszFormat)++)
702 {
703 /*
704 * Pretty function / method name printing.
705 * This isn't 100% right (see classic signal prototype) and it assumes
706 * standardized names, but it'll do for today.
707 */
708 case 'n':
709 {
710 const char *pszStart;
711 const char *psz = pszStart = va_arg(*pArgs, const char *);
712 if (!VALID_PTR(psz))
713 return pfnOutput(pvArgOutput, RT_STR_TUPLE("<null>"));
714
715 while ((ch = *psz) != '\0' && ch != '(')
716 {
717 if (RT_C_IS_BLANK(ch))
718 {
719 psz++;
720 while ((ch = *psz) != '\0' && (RT_C_IS_BLANK(ch) || ch == '('))
721 psz++;
722 if (ch)
723 pszStart = psz;
724 }
725 else if (ch == '(')
726 break;
727 else
728 psz++;
729 }
730
731 return pfnOutput(pvArgOutput, pszStart, psz - pszStart);
732 }
733
734 default:
735 AssertMsgFailed(("Invalid status code format type '%.10s'!\n", pszFormatOrg));
736 break;
737 }
738 break;
739 }
740
741
742 /*
743 * hex dumping and COM/XPCOM.
744 */
745 case 'h':
746 {
747 switch (*(*ppszFormat)++)
748 {
749 /*
750 * Hex stuff.
751 */
752 case 'x':
753 {
754 uint8_t *pu8 = va_arg(*pArgs, uint8_t *);
755 if (cchPrecision < 0)
756 cchPrecision = 16;
757 if (pu8)
758 {
759 switch (*(*ppszFormat)++)
760 {
761 /*
762 * Regular hex dump.
763 */
764 case 'd':
765 {
766 int off = 0;
767 cch = 0;
768
769 if (cchWidth <= 0)
770 cchWidth = 16;
771
772 while (off < cchPrecision)
773 {
774 int i;
775 cch += RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%s%0*p %04x:", off ? "\n" : "", sizeof(pu8) * 2, (uintptr_t)pu8, off);
776 for (i = 0; i < cchWidth && off + i < cchPrecision ; i++)
777 cch += RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
778 off + i < cchPrecision ? !(i & 7) && i ? "-%02x" : " %02x" : " ", pu8[i]);
779 while (i++ < cchWidth)
780 cch += pfnOutput(pvArgOutput, " ", 3);
781
782 cch += pfnOutput(pvArgOutput, " ", 1);
783
784 for (i = 0; i < cchWidth && off + i < cchPrecision; i++)
785 {
786 uint8_t u8 = pu8[i];
787 cch += pfnOutput(pvArgOutput, u8 < 127 && u8 >= 32 ? (const char *)&u8 : ".", 1);
788 }
789
790 /* next */
791 pu8 += cchWidth;
792 off += cchWidth;
793 }
794 return cch;
795 }
796
797 /*
798 * Hex string.
799 */
800 case 's':
801 {
802 if (cchPrecision-- > 0)
803 {
804 cch = RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%02x", *pu8++);
805 for (; cchPrecision > 0; cchPrecision--, pu8++)
806 cch += RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, " %02x", *pu8);
807 return cch;
808 }
809 break;
810 }
811
812 default:
813 AssertMsgFailed(("Invalid status code format type '%.10s'!\n", pszFormatOrg));
814 break;
815 }
816 }
817 else
818 return pfnOutput(pvArgOutput, RT_STR_TUPLE("<null>"));
819 break;
820 }
821
822
823#ifdef IN_RING3
824 /*
825 * XPCOM / COM status code: %Rhrc, %Rhrf, %Rhra
826 * ASSUMES: If Windows Then COM else XPCOM.
827 */
828 case 'r':
829 {
830 uint32_t hrc = va_arg(*pArgs, uint32_t);
831 PCRTCOMERRMSG pMsg = RTErrCOMGet(hrc);
832 switch (*(*ppszFormat)++)
833 {
834 case 'c':
835 return pfnOutput(pvArgOutput, pMsg->pszDefine, strlen(pMsg->pszDefine));
836 case 'f':
837 return pfnOutput(pvArgOutput, pMsg->pszMsgFull,strlen(pMsg->pszMsgFull));
838 case 'a':
839 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%s (0x%08X) - %s", pMsg->pszDefine, hrc, pMsg->pszMsgFull);
840 default:
841 AssertMsgFailed(("Invalid status code format type '%.10s'!\n", pszFormatOrg));
842 return 0;
843 }
844 break;
845 }
846#endif /* IN_RING3 */
847
848 default:
849 AssertMsgFailed(("Invalid status code format type '%.10s'!\n", pszFormatOrg));
850 return 0;
851
852 }
853 break;
854 }
855
856 /*
857 * iprt status code: %Rrc, %Rrs, %Rrf, %Rra.
858 */
859 case 'r':
860 {
861 int rc = va_arg(*pArgs, int);
862#ifdef IN_RING3 /* we don't want this anywhere else yet. */
863 PCRTSTATUSMSG pMsg = RTErrGet(rc);
864 switch (*(*ppszFormat)++)
865 {
866 case 'c':
867 return pfnOutput(pvArgOutput, pMsg->pszDefine, strlen(pMsg->pszDefine));
868 case 's':
869 return pfnOutput(pvArgOutput, pMsg->pszMsgShort, strlen(pMsg->pszMsgShort));
870 case 'f':
871 return pfnOutput(pvArgOutput, pMsg->pszMsgFull, strlen(pMsg->pszMsgFull));
872 case 'a':
873 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%s (%d) - %s", pMsg->pszDefine, rc, pMsg->pszMsgFull);
874 default:
875 AssertMsgFailed(("Invalid status code format type '%.10s'!\n", pszFormatOrg));
876 return 0;
877 }
878#else /* !IN_RING3 */
879 switch (*(*ppszFormat)++)
880 {
881 case 'c':
882 case 's':
883 case 'f':
884 case 'a':
885 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%d", rc);
886 default:
887 AssertMsgFailed(("Invalid status code format type '%.10s'!\n", pszFormatOrg));
888 return 0;
889 }
890#endif /* !IN_RING3 */
891 break;
892 }
893
894#if defined(IN_RING3)
895 /*
896 * Windows status code: %Rwc, %Rwf, %Rwa
897 */
898 case 'w':
899 {
900 long rc = va_arg(*pArgs, long);
901# if defined(RT_OS_WINDOWS)
902 PCRTWINERRMSG pMsg = RTErrWinGet(rc);
903# endif
904 switch (*(*ppszFormat)++)
905 {
906# if defined(RT_OS_WINDOWS)
907 case 'c':
908 return pfnOutput(pvArgOutput, pMsg->pszDefine, strlen(pMsg->pszDefine));
909 case 'f':
910 return pfnOutput(pvArgOutput, pMsg->pszMsgFull,strlen(pMsg->pszMsgFull));
911 case 'a':
912 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%s (0x%08X) - %s", pMsg->pszDefine, rc, pMsg->pszMsgFull);
913# else
914 case 'c':
915 case 'f':
916 case 'a':
917 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "0x%08X", rc);
918# endif
919 default:
920 AssertMsgFailed(("Invalid status code format type '%.10s'!\n", pszFormatOrg));
921 return 0;
922 }
923 break;
924 }
925#endif /* IN_RING3 */
926
927 /*
928 * Group 4, structure dumpers.
929 */
930 case 'D':
931 {
932 /*
933 * Interpret the type.
934 */
935 typedef enum
936 {
937 RTST_TIMESPEC
938 } RTST;
939/** Set if it's a pointer */
940#define RTST_FLAGS_POINTER RT_BIT(0)
941 static const struct
942 {
943 uint8_t cch; /**< the length of the string. */
944 char sz[16-2]; /**< the part following 'R'. */
945 uint8_t cb; /**< the size of the argument. */
946 uint8_t fFlags; /**< RTST_FLAGS_* */
947 RTST enmType; /**< The structure type. */
948 }
949 /** Sorted array of types, looked up using binary search! */
950 s_aTypes[] =
951 {
952#define STRMEM(str) sizeof(str) - 1, str
953 { STRMEM("Dtimespec"), sizeof(PCRTTIMESPEC), RTST_FLAGS_POINTER, RTST_TIMESPEC},
954#undef STRMEM
955 };
956 const char *pszType = *ppszFormat - 1;
957 int iStart = 0;
958 int iEnd = RT_ELEMENTS(s_aTypes) - 1;
959 int i = RT_ELEMENTS(s_aTypes) / 2;
960
961 union
962 {
963 const void *pv;
964 uint64_t u64;
965 PCRTTIMESPEC pTimeSpec;
966 } u;
967
968 AssertMsg(!chArgSize, ("Not argument size '%c' for RT types! '%.10s'\n", chArgSize, pszFormatOrg));
969
970 /*
971 * Lookup the type - binary search.
972 */
973 for (;;)
974 {
975 int iDiff = strncmp(pszType, s_aTypes[i].sz, s_aTypes[i].cch);
976 if (!iDiff)
977 break;
978 if (iEnd == iStart)
979 {
980 AssertMsgFailed(("Invalid format type '%.10s'!\n", pszFormatOrg));
981 return 0;
982 }
983 if (iDiff < 0)
984 iEnd = i - 1;
985 else
986 iStart = i + 1;
987 if (iEnd < iStart)
988 {
989 AssertMsgFailed(("Invalid format type '%.10s'!\n", pszFormatOrg));
990 return 0;
991 }
992 i = iStart + (iEnd - iStart) / 2;
993 }
994 *ppszFormat += s_aTypes[i].cch - 1;
995
996 /*
997 * Fetch the argument.
998 */
999 u.u64 = 0;
1000 switch (s_aTypes[i].cb)
1001 {
1002 case sizeof(const void *):
1003 u.pv = va_arg(*pArgs, const void *);
1004 break;
1005 default:
1006 AssertMsgFailed(("Invalid format error, size %d'!\n", s_aTypes[i].cb));
1007 break;
1008 }
1009
1010 /*
1011 * If it's a pointer, we'll check if it's valid before going on.
1012 */
1013 if ((s_aTypes[i].fFlags & RTST_FLAGS_POINTER) && !VALID_PTR(u.pv))
1014 return pfnOutput(pvArgOutput, RT_STR_TUPLE("<null>"));
1015
1016 /*
1017 * Format the output.
1018 */
1019 switch (s_aTypes[i].enmType)
1020 {
1021 case RTST_TIMESPEC:
1022 return RTStrFormat(pfnOutput, pvArgOutput, NULL, NULL, "%'lld ns", RTTimeSpecGetNano(u.pTimeSpec));
1023
1024 default:
1025 AssertMsgFailed(("Invalid/unhandled enmType=%d\n", s_aTypes[i].enmType));
1026 break;
1027 }
1028 break;
1029 }
1030
1031#ifdef IN_RING3
1032 /*
1033 * Group 5, XML / HTML escapers.
1034 */
1035 case 'M':
1036 {
1037 char chWhat = (*ppszFormat)[0];
1038 bool fAttr = chWhat == 'a';
1039 char chType = (*ppszFormat)[1];
1040 AssertMsgBreak(chWhat == 'a' || chWhat == 'e', ("Invalid IPRT format type '%.10s'!\n", pszFormatOrg));
1041 *ppszFormat += 2;
1042 switch (chType)
1043 {
1044 case 's':
1045 {
1046 static const char s_szElemEscape[] = "<>&\"'";
1047 static const char s_szAttrEscape[] = "<>&\"\n\r"; /* more? */
1048 const char * const pszEscape = fAttr ? s_szAttrEscape : s_szElemEscape;
1049 size_t const cchEscape = (fAttr ? RT_ELEMENTS(s_szAttrEscape) : RT_ELEMENTS(s_szElemEscape)) - 1;
1050 size_t cchOutput = 0;
1051 const char *pszStr = va_arg(*pArgs, char *);
1052 ssize_t cchStr;
1053 ssize_t offCur;
1054 ssize_t offLast;
1055
1056 if (!VALID_PTR(pszStr))
1057 pszStr = "<NULL>";
1058 cchStr = RTStrNLen(pszStr, (unsigned)cchPrecision);
1059
1060 if (fAttr)
1061 cchOutput += pfnOutput(pvArgOutput, "\"", 1);
1062 if (!(fFlags & RTSTR_F_LEFT))
1063 while (--cchWidth >= cchStr)
1064 cchOutput += pfnOutput(pvArgOutput, " ", 1);
1065
1066 offLast = offCur = 0;
1067 while (offCur < cchStr)
1068 {
1069 if (memchr(pszEscape, pszStr[offCur], cchEscape))
1070 {
1071 if (offLast < offCur)
1072 cchOutput += pfnOutput(pvArgOutput, &pszStr[offLast], offCur - offLast);
1073 switch (pszStr[offCur])
1074 {
1075 case '<': cchOutput += pfnOutput(pvArgOutput, "&lt;", 4); break;
1076 case '>': cchOutput += pfnOutput(pvArgOutput, "&gt;", 4); break;
1077 case '&': cchOutput += pfnOutput(pvArgOutput, "&amp;", 5); break;
1078 case '\'': cchOutput += pfnOutput(pvArgOutput, "&apos;", 6); break;
1079 case '"': cchOutput += pfnOutput(pvArgOutput, "&quot;", 6); break;
1080 case '\n': cchOutput += pfnOutput(pvArgOutput, "&#xA;", 5); break;
1081 case '\r': cchOutput += pfnOutput(pvArgOutput, "&#xD;", 5); break;
1082 default:
1083 AssertFailed();
1084 }
1085 offLast = offCur + 1;
1086 }
1087 offCur++;
1088 }
1089 if (offLast < offCur)
1090 cchOutput += pfnOutput(pvArgOutput, &pszStr[offLast], offCur - offLast);
1091
1092 while (--cchWidth >= cchStr)
1093 cchOutput += pfnOutput(pvArgOutput, " ", 1);
1094 if (fAttr)
1095 cchOutput += pfnOutput(pvArgOutput, "\"", 1);
1096 return cchOutput;
1097 }
1098
1099 default:
1100 AssertMsgFailed(("Invalid IPRT format type '%.10s'!\n", pszFormatOrg));
1101 }
1102 break;
1103 }
1104#endif /* IN_RING3 */
1105
1106
1107 /*
1108 * Groups 6 - CPU Architecture Register Formatters.
1109 * "%RAarch[reg]"
1110 */
1111 case 'A':
1112 {
1113 char const * const pszArch = *ppszFormat;
1114 const char *pszReg = pszArch;
1115 size_t cchOutput = 0;
1116 int cPrinted = 0;
1117 size_t cchReg;
1118
1119 /* Parse out the */
1120 while ((ch = *pszReg++) && ch != '[')
1121 { /* nothing */ }
1122 AssertMsgBreak(ch == '[', ("Malformed IPRT architecture register format type '%.10s'!\n", pszFormatOrg));
1123
1124 cchReg = 0;
1125 while ((ch = pszReg[cchReg]) && ch != ']')
1126 cchReg++;
1127 AssertMsgBreak(ch == ']', ("Malformed IPRT architecture register format type '%.10s'!\n", pszFormatOrg));
1128
1129 *ppszFormat = &pszReg[cchReg + 1];
1130
1131
1132#define REG_EQUALS(a_szReg) (sizeof(a_szReg) - 1 == cchReg && !strncmp(a_szReg, pszReg, sizeof(a_szReg) - 1))
1133#define REG_OUT_BIT(a_uVal, a_fBitMask, a_szName) \
1134 do { \
1135 if ((a_uVal) & (a_fBitMask)) \
1136 { \
1137 if (!cPrinted++) \
1138 cchOutput += pfnOutput(pvArgOutput, "{" a_szName, sizeof(a_szName)); \
1139 else \
1140 cchOutput += pfnOutput(pvArgOutput, "," a_szName, sizeof(a_szName)); \
1141 (a_uVal) &= ~(a_fBitMask); \
1142 } \
1143 } while (0)
1144#define REG_OUT_CLOSE(a_uVal) \
1145 do { \
1146 if ((a_uVal)) \
1147 { \
1148 cchOutput += pfnOutput(pvArgOutput, !cPrinted ? "{unkn=" : ",unkn=", 6); \
1149 cch = RTStrFormatNumber(&szBuf[0], (a_uVal), 16, 1, -1, fFlags); \
1150 cchOutput += pfnOutput(pvArgOutput, szBuf, cch); \
1151 cPrinted++; \
1152 } \
1153 if (cPrinted) \
1154 cchOutput += pfnOutput(pvArgOutput, "}", 1); \
1155 } while (0)
1156
1157
1158 if (0)
1159 { /* dummy */ }
1160#ifdef STRFORMAT_WITH_X86
1161 /*
1162 * X86 & AMD64.
1163 */
1164 else if ( pszReg - pszArch == 3 + 1
1165 && pszArch[0] == 'x'
1166 && pszArch[1] == '8'
1167 && pszArch[2] == '6')
1168 {
1169 if (REG_EQUALS("cr0"))
1170 {
1171 uint64_t cr0 = va_arg(*pArgs, uint64_t);
1172 fFlags |= RTSTR_F_64BIT;
1173 cch = RTStrFormatNumber(&szBuf[0], cr0, 16, 8, -1, fFlags | RTSTR_F_ZEROPAD);
1174 cchOutput += pfnOutput(pvArgOutput, szBuf, cch);
1175 REG_OUT_BIT(cr0, X86_CR0_PE, "PE");
1176 REG_OUT_BIT(cr0, X86_CR0_MP, "MP");
1177 REG_OUT_BIT(cr0, X86_CR0_EM, "EM");
1178 REG_OUT_BIT(cr0, X86_CR0_TS, "DE");
1179 REG_OUT_BIT(cr0, X86_CR0_ET, "ET");
1180 REG_OUT_BIT(cr0, X86_CR0_NE, "NE");
1181 REG_OUT_BIT(cr0, X86_CR0_WP, "WP");
1182 REG_OUT_BIT(cr0, X86_CR0_AM, "AM");
1183 REG_OUT_BIT(cr0, X86_CR0_NW, "NW");
1184 REG_OUT_BIT(cr0, X86_CR0_CD, "CD");
1185 REG_OUT_BIT(cr0, X86_CR0_PG, "PG");
1186 REG_OUT_CLOSE(cr0);
1187 }
1188 else if (REG_EQUALS("cr4"))
1189 {
1190 uint64_t cr4 = va_arg(*pArgs, uint64_t);
1191 fFlags |= RTSTR_F_64BIT;
1192 cch = RTStrFormatNumber(&szBuf[0], cr4, 16, 8, -1, fFlags | RTSTR_F_ZEROPAD);
1193 cchOutput += pfnOutput(pvArgOutput, szBuf, cch);
1194 REG_OUT_BIT(cr4, X86_CR4_VME, "VME");
1195 REG_OUT_BIT(cr4, X86_CR4_PVI, "PVI");
1196 REG_OUT_BIT(cr4, X86_CR4_TSD, "TSD");
1197 REG_OUT_BIT(cr4, X86_CR4_DE, "DE");
1198 REG_OUT_BIT(cr4, X86_CR4_PSE, "PSE");
1199 REG_OUT_BIT(cr4, X86_CR4_PAE, "PAE");
1200 REG_OUT_BIT(cr4, X86_CR4_MCE, "MCE");
1201 REG_OUT_BIT(cr4, X86_CR4_PGE, "PGE");
1202 REG_OUT_BIT(cr4, X86_CR4_PCE, "PCE");
1203 REG_OUT_BIT(cr4, X86_CR4_OSFXSR, "OSFXSR");
1204 REG_OUT_BIT(cr4, X86_CR4_OSXMMEEXCPT, "OSXMMEEXCPT");
1205 REG_OUT_BIT(cr4, X86_CR4_VMXE, "VMXE");
1206 REG_OUT_BIT(cr4, X86_CR4_SMXE, "SMXE");
1207 REG_OUT_BIT(cr4, X86_CR4_PCIDE, "PCIDE");
1208 REG_OUT_BIT(cr4, X86_CR4_OSXSAVE, "OSXSAVE");
1209 REG_OUT_BIT(cr4, X86_CR4_SMEP, "SMEP");
1210 REG_OUT_BIT(cr4, X86_CR4_SMAP, "SMAP");
1211 REG_OUT_CLOSE(cr4);
1212 }
1213 else
1214 AssertMsgFailed(("Unknown x86 register specified in '%.10s'!\n", pszFormatOrg));
1215 }
1216#endif
1217 else
1218 AssertMsgFailed(("Unknown architecture specified in '%.10s'!\n", pszFormatOrg));
1219#undef REG_OUT_BIT
1220#undef REG_OUT_CLOSE
1221#undef REG_EQUALS
1222 return cchOutput;
1223 }
1224
1225 /*
1226 * Invalid/Unknown. Bitch about it.
1227 */
1228 default:
1229 AssertMsgFailed(("Invalid IPRT format type '%.10s'!\n", pszFormatOrg));
1230 break;
1231 }
1232 }
1233 else
1234 AssertMsgFailed(("Invalid IPRT format type '%.10s'!\n", pszFormatOrg));
1235
1236 NOREF(pszFormatOrg);
1237 return 0;
1238}
1239
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette