Merge tag 'trace-v4.16' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt...
[linux-2.6-block.git] / lib / vsprintf.c
index 2b18135446dcb89c89d4c0875ff504d798f17d9b..8f56cdd52149ba90fb4013a7ebf072a2992a5e05 100644 (file)
@@ -2517,29 +2517,34 @@ int vbin_printf(u32 *bin_buf, size_t size, const char *fmt, va_list args)
 {
        struct printf_spec spec = {0};
        char *str, *end;
+       int width;
 
        str = (char *)bin_buf;
        end = (char *)(bin_buf + size);
 
 #define save_arg(type)                                                 \
-do {                                                                   \
+({                                                                     \
+       unsigned long long value;                                       \
        if (sizeof(type) == 8) {                                        \
-               unsigned long long value;                               \
+               unsigned long long val8;                                \
                str = PTR_ALIGN(str, sizeof(u32));                      \
-               value = va_arg(args, unsigned long long);               \
+               val8 = va_arg(args, unsigned long long);                \
                if (str + sizeof(type) <= end) {                        \
-                       *(u32 *)str = *(u32 *)&value;                   \
-                       *(u32 *)(str + 4) = *((u32 *)&value + 1);       \
+                       *(u32 *)str = *(u32 *)&val8;                    \
+                       *(u32 *)(str + 4) = *((u32 *)&val8 + 1);        \
                }                                                       \
+               value = val8;                                           \
        } else {                                                        \
-               unsigned long value;                                    \
+               unsigned int val4;                                      \
                str = PTR_ALIGN(str, sizeof(type));                     \
-               value = va_arg(args, int);                              \
+               val4 = va_arg(args, int);                               \
                if (str + sizeof(type) <= end)                          \
-                       *(typeof(type) *)str = (type)value;             \
+                       *(typeof(type) *)str = (type)(long)val4;        \
+               value = (unsigned long long)val4;                       \
        }                                                               \
        str += sizeof(type);                                            \
-} while (0)
+       value;                                                          \
+})
 
        while (*fmt) {
                int read = format_decode(fmt, &spec);
@@ -2555,7 +2560,10 @@ do {                                                                     \
 
                case FORMAT_TYPE_WIDTH:
                case FORMAT_TYPE_PRECISION:
-                       save_arg(int);
+                       width = (int)save_arg(int);
+                       /* Pointers may require the width */
+                       if (*fmt == 'p')
+                               set_field_width(&spec, width);
                        break;
 
                case FORMAT_TYPE_CHAR:
@@ -2577,7 +2585,27 @@ do {                                                                     \
                }
 
                case FORMAT_TYPE_PTR:
-                       save_arg(void *);
+                       /* Dereferenced pointers must be done now */
+                       switch (*fmt) {
+                       /* Dereference of functions is still OK */
+                       case 'S':
+                       case 's':
+                       case 'F':
+                       case 'f':
+                               save_arg(void *);
+                               break;
+                       default:
+                               if (!isalnum(*fmt)) {
+                                       save_arg(void *);
+                                       break;
+                               }
+                               str = pointer(fmt, str, end, va_arg(args, void *),
+                                             spec);
+                               if (str + 1 < end)
+                                       *str++ = '\0';
+                               else
+                                       end[-1] = '\0'; /* Must be nul terminated */
+                       }
                        /* skip all alphanumeric pointer suffixes */
                        while (isalnum(*fmt))
                                fmt++;
@@ -2729,11 +2757,39 @@ int bstr_printf(char *buf, size_t size, const char *fmt, const u32 *bin_buf)
                        break;
                }
 
-               case FORMAT_TYPE_PTR:
-                       str = pointer(fmt, str, end, get_arg(void *), spec);
+               case FORMAT_TYPE_PTR: {
+                       bool process = false;
+                       int copy, len;
+                       /* Non function dereferences were already done */
+                       switch (*fmt) {
+                       case 'S':
+                       case 's':
+                       case 'F':
+                       case 'f':
+                               process = true;
+                               break;
+                       default:
+                               if (!isalnum(*fmt)) {
+                                       process = true;
+                                       break;
+                               }
+                               /* Pointer dereference was already processed */
+                               if (str < end) {
+                                       len = copy = strlen(args);
+                                       if (copy > end - str)
+                                               copy = end - str;
+                                       memcpy(str, args, copy);
+                                       str += len;
+                                       args += len;
+                               }
+                       }
+                       if (process)
+                               str = pointer(fmt, str, end, get_arg(void *), spec);
+
                        while (isalnum(*fmt))
                                fmt++;
                        break;
+               }
 
                case FORMAT_TYPE_PERCENT_CHAR:
                        if (str < end)