fix(dlog): fix bug in handling of `%*`

The `dlog` function was not handling the `%*` format specifier
correctly.

The bug was caused by passing `va_list` by value instead of by
reference: In a call like `dlog("%*s", 10, "hello")`, the `va_list`
argument would be copied when passed to `parse_min_width`, and `10`
would be popped from the `va_list` to be used as the min_width. But then
`10` would be popped again and used as the `%s` argument, rather than
"hello".

Change-Id: I5c53465384196ee21d2a63167cf82e4f8ead9c3a
Signed-off-by: Karl Meakin <karl.meakin@arm.com>
diff --git a/src/dlog.c b/src/dlog.c
index 780cf55..aa174d1 100644
--- a/src/dlog.c
+++ b/src/dlog.c
@@ -317,7 +317,8 @@
  *
  * Returns a pointer to the first non-digit character in the string.
  */
-static const char *parse_min_width(const char *fmt, va_list args,
+static const char *parse_min_width(const char *fmt,
+				   struct va_list_wrapper *args,
 				   struct format_flags *flags, int *min_width)
 {
 	int width = 0;
@@ -325,7 +326,7 @@
 	/* Read minimum width from arguments. */
 	if (*fmt == '*') {
 		fmt++;
-		width = va_arg(args, int);
+		width = va_arg(args->va, int);
 		if (width < 0) {
 			width = -width;
 			flags->minus = true;
@@ -408,7 +409,7 @@
  *
  * Returns number of characters written, or `-1` if format string is invalid.
  */
-size_t vdlog(const char *fmt, va_list args)
+size_t vdlog(const char *fmt, struct va_list_wrapper *args)
 {
 	size_t chars_written = 0;
 
@@ -442,7 +443,7 @@
 				break;
 
 			case 'c': {
-				char str[2] = {va_arg(args, int), 0};
+				char str[2] = {va_arg(args->va, int), '\0'};
 
 				fmt++;
 				chars_written += print_string(
@@ -451,7 +452,7 @@
 			}
 
 			case 's': {
-				char *str = va_arg(args, char *);
+				char *str = va_arg(args->va, char *);
 
 				fmt++;
 				chars_written += print_string(
@@ -462,7 +463,7 @@
 			case 'd':
 			case 'i': {
 				fmt++;
-				value = va_arg(args, uint64_t);
+				value = va_arg(args->va, uint64_t);
 				value = reinterpret_signed_int(length, value,
 							       &flags);
 
@@ -473,7 +474,7 @@
 
 			case 'b':
 				fmt++;
-				value = va_arg(args, uint64_t);
+				value = va_arg(args->va, uint64_t);
 				value = reinterpret_unsigned_int(length, value);
 
 				chars_written += print_int(value, base2,
@@ -483,7 +484,7 @@
 			case 'B':
 				fmt++;
 				flags.upper = true;
-				value = va_arg(args, uint64_t);
+				value = va_arg(args->va, uint64_t);
 				value = reinterpret_unsigned_int(length, value);
 
 				chars_written += print_int(value, base2,
@@ -492,7 +493,7 @@
 
 			case 'o':
 				fmt++;
-				value = va_arg(args, uint64_t);
+				value = va_arg(args->va, uint64_t);
 				value = reinterpret_unsigned_int(length, value);
 
 				chars_written += print_int(value, base8,
@@ -501,7 +502,7 @@
 
 			case 'x':
 				fmt++;
-				value = va_arg(args, uint64_t);
+				value = va_arg(args->va, uint64_t);
 				value = reinterpret_unsigned_int(length, value);
 
 				chars_written += print_int(value, base16,
@@ -511,7 +512,7 @@
 			case 'X':
 				fmt++;
 				flags.upper = true;
-				value = va_arg(args, uint64_t);
+				value = va_arg(args->va, uint64_t);
 				value = reinterpret_unsigned_int(length, value);
 
 				chars_written += print_int(value, base16,
@@ -520,7 +521,7 @@
 
 			case 'u':
 				fmt++;
-				value = va_arg(args, uint64_t);
+				value = va_arg(args->va, uint64_t);
 				value = reinterpret_unsigned_int(length, value);
 
 				chars_written += print_int(value, base10,
@@ -529,7 +530,7 @@
 
 			case 'p':
 				fmt++;
-				value = va_arg(args, uint64_t);
+				value = va_arg(args->va, uint64_t);
 				min_width = sizeof(size_t) * 2 + 2;
 				flags.zero = true;
 				flags.alt = true;
@@ -569,10 +570,10 @@
 size_t dlog(const char *fmt, ...)
 {
 	size_t chars_written = 0;
-	va_list args;
+	struct va_list_wrapper args;
 
-	va_start(args, fmt);
-	chars_written = vdlog(fmt, args);
-	va_end(args);
+	va_start(args.va, fmt);
+	chars_written = vdlog(fmt, &args);
+	va_end(args.va);
 	return chars_written;
 }