VirtualBox

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

Last change on this file since 54864 was 54864, checked in by vboxsync, 10 years ago

Missing typo fix.

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

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