From 5d8cdeaea847bcaf0b9145dd922e0a83045067ca Mon Sep 17 00:00:00 2001 From: yinshengkai Date: Wed, 29 Nov 2023 12:35:29 +0800 Subject: [PATCH] note: print without relying on format strings Signed-off-by: yinshengkai --- drivers/note/Kconfig | 5 + drivers/note/note_driver.c | 344 ++++++++++++++++++++-------------- drivers/note/noteram_driver.c | 233 ++++++++++++++--------- include/nuttx/compiler.h | 8 +- include/nuttx/macro.h | 140 ++++++++++++++ include/nuttx/sched_note.h | 86 ++++++++- sched/Kconfig | 4 +- 7 files changed, 580 insertions(+), 240 deletions(-) create mode 100644 include/nuttx/macro.h diff --git a/drivers/note/Kconfig b/drivers/note/Kconfig index 49248bd121..e5469b6ab9 100644 --- a/drivers/note/Kconfig +++ b/drivers/note/Kconfig @@ -87,6 +87,11 @@ config DRIVERS_NOTERAM_CRASH_DUMP endif # DRIVERS_NOTERAM +config DRIVERS_NOTE_STRIP_FORMAT + bool "Strip sched_note_printf format string" + ---help--- + Strip sched_note_printf format string. + config DRIVERS_NOTELOG bool "Note syslog driver" ---help--- diff --git a/drivers/note/note_driver.c b/drivers/note/note_driver.c index ea58c8be17..0b4d725c67 100644 --- a/drivers/note/note_driver.c +++ b/drivers/note/note_driver.c @@ -1483,39 +1483,14 @@ void sched_note_event_ip(uint32_t tag, uintptr_t ip, uint8_t event, } } -void sched_note_vprintf_ip(uint32_t tag, uintptr_t ip, - FAR const char *fmt, va_list va) +void sched_note_vprintf_ip(uint32_t tag, uintptr_t ip, FAR const char *fmt, + uint32_t type, va_list va) { FAR struct note_printf_s *note; FAR struct note_driver_s **driver; bool formatted = false; uint8_t data[255]; - begin_packed_struct union - { - int i; - long l; -#ifdef CONFIG_HAVE_LONG_LONG - long long ll; -#endif - intmax_t im; - size_t sz; - ptrdiff_t ptr; - FAR void *p; -#ifdef CONFIG_HAVE_DOUBLE - double d; -# ifdef CONFIG_HAVE_LONG_DOUBLE - long double ld; -# endif -#endif - } - - end_packed_struct *var; - - char c; - size_t length; - size_t next = 0; - bool infmt = false; - FAR const char *p = fmt; + size_t length = 0; FAR struct tcb_s *tcb = this_task(); if (!note_isenabled_dump(tag)) @@ -1539,146 +1514,236 @@ void sched_note_vprintf_ip(uint32_t tag, uintptr_t ip, if (!formatted) { + begin_packed_struct union + { + int i; + long l; +#ifdef CONFIG_HAVE_LONG_LONG + long long ll; +#endif + intmax_t im; + size_t sz; + ptrdiff_t ptr; + FAR void *p; + FAR const char *s; +#ifdef CONFIG_HAVE_DOUBLE + double d; +# ifdef CONFIG_HAVE_LONG_DOUBLE + long double ld; +# endif +#endif + } + + end_packed_struct *var; + size_t next = 0; formatted = true; note = (FAR struct note_printf_s *)data; length = sizeof(data) - SIZEOF_NOTE_PRINTF(0); - while ((c = *p++) != '\0') + if (type) { - if (c != '%' && !infmt) + size_t count = NOTE_PRINTF_GET_COUNT(type); + size_t i; + + for (i = 0; i < count; i++) { - continue; + var = (FAR void *)¬e->npt_data[next]; + switch (NOTE_PRINTF_GET_TYPE(type, i)) + { + case NOTE_PRINTF_UINT32: + { + var->i = va_arg(va, int); + if (next + sizeof(var->i) > length) + { + break; + } + + next += sizeof(var->i); + } + break; + case NOTE_PRINTF_UINT64: + { + if (next + sizeof(var->ll) > length) + { + break; + } + + var->ll = va_arg(va, long long); + next += sizeof(var->ll); + } + break; + case NOTE_PRINTF_STRING: + { + size_t len; + var->s = va_arg(va, FAR const char *); + len = strlen(var->s) + 1; + if (next + len > length) + { + len = length - next; + } + + strlcpy(note->npt_data + next, var->s, len); + next += len; + } + break; + case NOTE_PRINTF_DOUBLE: + { + var->d = va_arg(va, double); + if (next + sizeof(var->d) > length) + { + break; + } + + next += sizeof(var->d); + } + break; + } } + } + else + { + FAR const char *p = fmt; + bool infmt = false; + char c; - infmt = true; - var = (FAR void *)¬e->npt_data[next]; - - if (c == 'c' || c == 'd' || c == 'i' || c == 'u' || - c == 'o' || c == 'x' || c == 'X') + while ((c = *p++) != '\0') { - if (*(p - 2) == 'j') + if (c != '%' && !infmt) { - if (next + sizeof(var->im) > length) - { - break; - } - - var->im = va_arg(va, intmax_t); - next += sizeof(var->im); + continue; } + + infmt = true; + var = (FAR void *)¬e->npt_data[next]; + + if (c == 'c' || c == 'd' || c == 'i' || c == 'u' || + c == 'o' || c == 'x' || c == 'X') + { + if (*(p - 2) == 'j') + { + if (next + sizeof(var->im) > length) + { + break; + } + + var->im = va_arg(va, intmax_t); + next += sizeof(var->im); + } #ifdef CONFIG_HAVE_LONG_LONG - else if (*(p - 2) == 'l' && *(p - 3) == 'l') - { - if (next + sizeof(var->ll) > length) + else if (*(p - 2) == 'l' && *(p - 3) == 'l') { - break; - } + if (next + sizeof(var->ll) > length) + { + break; + } - var->ll = va_arg(va, long long); - next += sizeof(var->ll); - } + var->ll = va_arg(va, long long); + next += sizeof(var->ll); + } #endif - else if (*(p - 2) == 'l') - { - if (next + sizeof(var->l) > length) + else if (*(p - 2) == 'l') { - break; + if (next + sizeof(var->l) > length) + { + break; + } + + var->l = va_arg(va, long); + next += sizeof(var->l); + } + else if (*(p - 2) == 'z') + { + if (next + sizeof(var->sz) > length) + { + break; + } + + var->sz = va_arg(va, size_t); + next += sizeof(var->sz); + } + else if (*(p - 2) == 't') + { + if (next + sizeof(var->ptr) > length) + { + break; + } + + var->ptr = va_arg(va, ptrdiff_t); + next += sizeof(var->ptr); + } + else + { + if (next + sizeof(var->i) > length) + { + break; + } + + var->i = va_arg(va, int); + next += sizeof(var->i); } - var->l = va_arg(va, long); - next += sizeof(var->l); + infmt = false; } - else if (*(p - 2) == 'z') + else if (c == 'e' || c == 'f' || c == 'g' || c == 'a' || + c == 'A' || c == 'E' || c == 'F' || c == 'G') { - if (next + sizeof(var->sz) > length) +#ifdef CONFIG_HAVE_DOUBLE +# ifdef CONFIG_HAVE_LONG_DOUBLE + if (*(p - 2) == 'L') { - break; - } + if (next + sizeof(var->ld) > length) + { + break; + } - var->sz = va_arg(va, size_t); - next += sizeof(var->sz); + var->ld = va_arg(va, long double); + next += sizeof(var->ld); + } + else +# endif + { + if (next + sizeof(var->d) > length) + { + break; + } + + var->d = va_arg(va, double); + next += sizeof(var->d); + } +#endif + + infmt = false; } - else if (*(p - 2) == 't') + else if (c == '*') { - if (next + sizeof(var->ptr) > length) - { - break; - } - - var->ptr = va_arg(va, ptrdiff_t); - next += sizeof(var->ptr); - } - else - { - if (next + sizeof(var->i) > length) - { - break; - } - var->i = va_arg(va, int); next += sizeof(var->i); } - - infmt = false; - } - else if (c == 'e' || c == 'f' || c == 'g' || c == 'a' || - c == 'A' || c == 'E' || c == 'F' || c == 'G') - { -#ifdef CONFIG_HAVE_DOUBLE -# ifdef CONFIG_HAVE_LONG_DOUBLE - if (*(p - 2) == 'L') + else if (c == 's') { - if (next + sizeof(var->ld) > length) + size_t len; + var->s = va_arg(va, FAR char *); + len = strlen(var->s) + 1; + if (next + len > length) + { + len = length - next; + } + + strlcpy(note->npt_data + next, var->s, len); + next += len; + infmt = false; + } + else if (c == 'p') + { + if (next + sizeof(var->p) > length) { break; } - var->ld = va_arg(va, long double); - next += sizeof(var->ld); + var->p = va_arg(va, FAR void *); + next += sizeof(var->p); + infmt = false; } - else -# endif - { - if (next + sizeof(var->d) > length) - { - break; - } - - var->d = va_arg(va, double); - next += sizeof(var->d); - } -#endif - - infmt = false; - } - else if (c == '*') - { - var->i = va_arg(va, int); - next += sizeof(var->i); - } - else if (c == 's') - { - FAR char *str = (FAR char *)va_arg(va, FAR char *); - size_t len = strlen(str) + 1; - if (next + len > length) - { - len = length - next; - } - - strlcpy(¬e->npt_data[next], str, len); - next += len; - infmt = false; - } - else if (c == 'p') - { - if (next + sizeof(var->p) > length) - { - break; - } - - var->p = va_arg(va, FAR void *); - next += sizeof(var->p); - infmt = false; } } @@ -1686,6 +1751,7 @@ void sched_note_vprintf_ip(uint32_t tag, uintptr_t ip, note_common(tcb, ¬e->npt_cmn, length, NOTE_DUMP_PRINTF); note->npt_ip = ip; note->npt_fmt = fmt; + note->npt_type = type; } /* Add the note to circular buffer */ @@ -1694,12 +1760,12 @@ void sched_note_vprintf_ip(uint32_t tag, uintptr_t ip, } } -void sched_note_printf_ip(uint32_t tag, uintptr_t ip, - FAR const char *fmt, ...) +void sched_note_printf_ip(uint32_t tag, uintptr_t ip, FAR const char *fmt, + uint32_t type, ...) { va_list va; - va_start(va, fmt); - sched_note_vprintf_ip(tag, ip, fmt, va); + va_start(va, type); + sched_note_vprintf_ip(tag, ip, fmt, type, va); va_end(va); } diff --git a/drivers/note/noteram_driver.c b/drivers/note/noteram_driver.c index 75400f1edd..c29447a28a 100644 --- a/drivers/note/noteram_driver.c +++ b/drivers/note/noteram_driver.c @@ -728,7 +728,8 @@ static int noteram_dump_printf(FAR struct lib_outstream_s *s, intmax_t im; size_t sz; ptrdiff_t pd; - uintptr_t p; + FAR void *p; + FAR const char *s; #ifdef CONFIG_HAVE_DOUBLE double d; # ifdef CONFIG_HAVE_LONG_DOUBLE @@ -738,117 +739,169 @@ static int noteram_dump_printf(FAR struct lib_outstream_s *s, } end_packed_struct *var; - FAR const char *p = note->npt_fmt; - FAR char *data = note->npt_data; - char fmtstr[64]; - bool infmt = false; size_t offset = 0; size_t ret = 0; size_t len = 0; - char c; - while ((c = *p++) != '\0') + if (note->npt_type == 0) { - if (c != '%' && !infmt) - { - lib_stream_putc(s, c); - ret++; - continue; - } + FAR const char *p = note->npt_fmt; + bool infmt = false; + char fmtstr[64]; + char c; - if (!infmt) + while ((c = *p++) != '\0') { - len = 0; - infmt = true; - memset(fmtstr, 0, sizeof(fmtstr)); - } - - var = (FAR void *)(note->npt_data + offset); - fmtstr[len++] = c; - - if (c == 'c' || c == 'd' || c == 'i' || c == 'u' || - c == 'o' || c == 'x' || c == 'X') - { - if (*(p - 2) == 'j') + if (c != '%' && !infmt) { - offset += sizeof(var->im); - ret += lib_sprintf(s, fmtstr, var->im); + lib_stream_putc(s, c); + ret++; + continue; } + + if (!infmt) + { + len = 0; + infmt = true; + memset(fmtstr, 0, sizeof(fmtstr)); + } + + var = (FAR void *)(note->npt_data + offset); + fmtstr[len++] = c; + + if (c == 'c' || c == 'd' || c == 'i' || c == 'u' || + c == 'o' || c == 'x' || c == 'X') + { + if (*(p - 2) == 'j') + { + offset += sizeof(var->im); + ret += lib_sprintf(s, fmtstr, var->im); + } #ifdef CONFIG_HAVE_LONG_LONG - else if (*(p - 2) == 'l' && *(p - 3) == 'l') - { - offset += sizeof(var->ll); - ret += lib_sprintf(s, fmtstr, var->ll); - } + else if (*(p - 2) == 'l' && *(p - 3) == 'l') + { + offset += sizeof(var->ll); + ret += lib_sprintf(s, fmtstr, var->ll); + } #endif - else if (*(p - 2) == 'l') - { - offset += sizeof(var->l); - ret += lib_sprintf(s, fmtstr, var->l); - } - else if (*(p - 2) == 'z') - { - offset += sizeof(var->sz); - ret += lib_sprintf(s, fmtstr, var->sz); - } - else if (*(p - 2) == 't') - { - offset += sizeof(var->pd); - ret += lib_sprintf(s, fmtstr, var->pd); - } - else - { - offset += sizeof(var->i); - ret += lib_sprintf(s, fmtstr, var->i); - } + else if (*(p - 2) == 'l') + { + offset += sizeof(var->l); + ret += lib_sprintf(s, fmtstr, var->l); + } + else if (*(p - 2) == 'z') + { + offset += sizeof(var->sz); + ret += lib_sprintf(s, fmtstr, var->sz); + } + else if (*(p - 2) == 't') + { + offset += sizeof(var->pd); + ret += lib_sprintf(s, fmtstr, var->pd); + } + else + { + offset += sizeof(var->i); + ret += lib_sprintf(s, fmtstr, var->i); + } - infmt = false; - } - else if (c == 'e' || c == 'f' || c == 'g' || c == 'a' || - c == 'A' || c == 'E' || c == 'F' || c == 'G') - { + infmt = false; + } + else if (c == 'e' || c == 'f' || c == 'g' || c == 'a' || + c == 'A' || c == 'E' || c == 'F' || c == 'G') + { #ifdef CONFIG_HAVE_DOUBLE # ifdef CONFIG_HAVE_LONG_DOUBLE - if (*(p - 2) == 'L') - { - offset += sizeof(var->ld); - ret += lib_sprintf(s, fmtstr, var->ld); - } - else + if (*(p - 2) == 'L') + { + offset += sizeof(var->ld); + ret += lib_sprintf(s, fmtstr, var->ld); + } + else # endif - { - offset += sizeof(var->d); - ret += lib_sprintf(s, fmtstr, var->d); - } + { + offset += sizeof(var->d); + ret += lib_sprintf(s, fmtstr, var->d); + } - infmt = false; - } + infmt = false; + } #endif - else if (c == '*') - { - itoa(var->i, fmtstr + len - 1, 10); - len = strlen(fmtstr); - offset += sizeof(var->i); + else if (c == '*') + { + itoa(var->i, fmtstr + len - 1, 10); + len = strlen(fmtstr); + offset += sizeof(var->i); + } + else if (c == 's') + { + const char *str = note->npt_data + offset; + offset += strlen(str) + 1; + ret += lib_sprintf(s, fmtstr, str); + infmt = false; + } + else if (c == 'p') + { + offset += sizeof(var->p); + ret += lib_sprintf(s, fmtstr, var->p); + infmt = false; + } } - else if (c == 's') + + if (*(p - 2) != '\n') { - FAR const char *value = data + offset; - offset += strlen(value) + 1; - ret += lib_sprintf(s, fmtstr, value); - infmt = false; - } - else if (c == 'p') - { - offset += sizeof(var->p); - ret += lib_sprintf(s, fmtstr, var->p); - infmt = false; + lib_stream_putc(s, '\n'); + ret++; } } - - if (*(p - 2) != '\n') + else { - lib_stream_putc(s, '\n'); - ret++; + size_t count = NOTE_PRINTF_GET_COUNT(note->npt_type); + size_t i; + + len = strlen(note->npt_fmt); + if (note->npt_fmt[len - 1] == '\n') + { + len--; + } + + ret += lib_sprintf(s, "%p", note->npt_fmt); + for (i = 0; i < count; i++) + { + int type = NOTE_PRINTF_GET_TYPE(note->npt_type, i); + var = (FAR void *)(note->npt_data + offset); + + switch (type) + { + case NOTE_PRINTF_UINT32: + { + offset += sizeof(var->i); + ret += lib_sprintf(s, " %u", var->i); + } + break; + case NOTE_PRINTF_UINT64: + { + offset += sizeof(var->ll); + ret += lib_sprintf(s, " %llu", var->ll); + } + break; + case NOTE_PRINTF_STRING: + { + const char *str = note->npt_data + offset; + offset += strlen(str) + 1; + ret += lib_sprintf(s, " %s", str); + } + break; + case NOTE_PRINTF_DOUBLE: + { + offset += sizeof(var->d); + ret += lib_sprintf(s, " %f", var->d); + } + } + } + + lib_stream_putc(s, '\n'); + ret++; } return ret; diff --git a/include/nuttx/compiler.h b/include/nuttx/compiler.h index dc994002e4..4658e26aff 100644 --- a/include/nuttx/compiler.h +++ b/include/nuttx/compiler.h @@ -172,7 +172,7 @@ * unnecessary "weak" functions can be excluded from the link. */ -#undef CONFIG_HAVE_WEAKFUNCTIONS +# undef CONFIG_HAVE_WEAKFUNCTIONS # if !defined(__CYGWIN__) && !defined(CONFIG_ARCH_GNU_NO_WEAKFUNCTIONS) # define CONFIG_HAVE_WEAKFUNCTIONS 1 @@ -344,6 +344,7 @@ # define syslog_like(a, b) __attribute__((__format__(__syslog__, a, b))) # define scanf_like(a, b) __attribute__((__format__(__scanf__, a, b))) # define strftime_like(a) __attribute__((__format__(__strftime__, a, 0))) +# define object_size(o, t) __builtin_object_size(o, t) /* GCC does not use storage classes to qualify addressing */ @@ -612,6 +613,7 @@ # define syslog_like(a, b) # define scanf_like(a, b) # define strftime_like(a) +# define object_size(o, t) ((size_t)-1) /* The reentrant attribute informs SDCC that the function * must be reentrant. In this case, SDCC will store input @@ -756,6 +758,7 @@ # define syslog_like(a, b) # define scanf_like(a, b) # define strftime_like(a) +# define object_size(o, t) ((size_t)-1) /* REVISIT: */ @@ -871,6 +874,7 @@ # define syslog_like(a, b) # define scanf_like(a, b) # define strftime_like(a) +# define object_size(o, t) ((size_t)-1) # define FAR # define NEAR @@ -1049,6 +1053,7 @@ # define syslog_like(a, b) # define scanf_like(a, b) # define strftime_like(a) +# define object_size(o, t) ((size_t)-1) # define FAR # define NEAR @@ -1118,6 +1123,7 @@ # define syslog_like(a, b) # define scanf_like(a, b) # define strftime_like(a) +# define object_size(o, t) ((size_t)-1) # define FAR # define NEAR diff --git a/include/nuttx/macro.h b/include/nuttx/macro.h new file mode 100644 index 0000000000..c9c2481430 --- /dev/null +++ b/include/nuttx/macro.h @@ -0,0 +1,140 @@ +/**************************************************************************** + * include/nuttx/macro.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __INCLUDE_NUTTX_MACRO_H +#define __INCLUDE_NUTTX_MACRO_H + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define GET_ARG_VALUE(_00, _01, _02, _03, _04, _05, _06, _07, \ + _08, _09, _10, _11, _12, _13, _14, _15, \ + _16, _17, _18, _19, _20, _21, _22, _23, \ + _24, _25, _26, _27, _28, _29, _30, _31, \ + _32, name, ...) name + +/* Get the number of arguments (up to 32) */ + +#define GET_ARG_COUNT(...) \ + GET_ARG_VALUE(_0, ##__VA_ARGS__, 32, 31, 30, \ + 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, \ + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, \ + 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) + +/* Reverse the arguments */ + +#define EXPAND(x) x + +#define REVERSE_00() +#define REVERSE_01(a) a +#define REVERSE_02(a,b) b,a +#define REVERSE_03(a,...) EXPAND(REVERSE_02(__VA_ARGS__)),a +#define REVERSE_04(a,...) EXPAND(REVERSE_03(__VA_ARGS__)),a +#define REVERSE_05(a,...) EXPAND(REVERSE_04(__VA_ARGS__)),a +#define REVERSE_06(a,...) EXPAND(REVERSE_05(__VA_ARGS__)),a +#define REVERSE_07(a,...) EXPAND(REVERSE_06(__VA_ARGS__)),a +#define REVERSE_08(a,...) EXPAND(REVERSE_07(__VA_ARGS__)),a +#define REVERSE_09(a,...) EXPAND(REVERSE_08(__VA_ARGS__)),a +#define REVERSE_10(a,...) EXPAND(REVERSE_09(__VA_ARGS__)),a +#define REVERSE_11(a,...) EXPAND(REVERSE_10(__VA_ARGS__)),a +#define REVERSE_12(a,...) EXPAND(REVERSE_11(__VA_ARGS__)),a +#define REVERSE_13(a,...) EXPAND(REVERSE_12(__VA_ARGS__)),a +#define REVERSE_14(a,...) EXPAND(REVERSE_13(__VA_ARGS__)),a +#define REVERSE_15(a,...) EXPAND(REVERSE_14(__VA_ARGS__)),a +#define REVERSE_16(a,...) EXPAND(REVERSE_15(__VA_ARGS__)),a +#define REVERSE_17(a,...) EXPAND(REVERSE_16(__VA_ARGS__)),a +#define REVERSE_18(a,...) EXPAND(REVERSE_17(__VA_ARGS__)),a +#define REVERSE_19(a,...) EXPAND(REVERSE_18(__VA_ARGS__)),a +#define REVERSE_20(a,...) EXPAND(REVERSE_19(__VA_ARGS__)),a +#define REVERSE_21(a,...) EXPAND(REVERSE_20(__VA_ARGS__)),a +#define REVERSE_22(a,...) EXPAND(REVERSE_21(__VA_ARGS__)),a +#define REVERSE_23(a,...) EXPAND(REVERSE_22(__VA_ARGS__)),a +#define REVERSE_24(a,...) EXPAND(REVERSE_23(__VA_ARGS__)),a +#define REVERSE_25(a,...) EXPAND(REVERSE_24(__VA_ARGS__)),a +#define REVERSE_26(a,...) EXPAND(REVERSE_25(__VA_ARGS__)),a +#define REVERSE_27(a,...) EXPAND(REVERSE_26(__VA_ARGS__)),a +#define REVERSE_28(a,...) EXPAND(REVERSE_27(__VA_ARGS__)),a +#define REVERSE_29(a,...) EXPAND(REVERSE_28(__VA_ARGS__)),a +#define REVERSE_30(a,...) EXPAND(REVERSE_29(__VA_ARGS__)),a +#define REVERSE_31(a,...) EXPAND(REVERSE_30(__VA_ARGS__)),a +#define REVERSE_32(a,...) EXPAND(REVERSE_31(__VA_ARGS__)),a + +#define REVERSE_ARG_(...) \ + GET_ARG_VALUE(0, ##__VA_ARGS__, \ + REVERSE_32, REVERSE_31, REVERSE_30, REVERSE_29, REVERSE_28, REVERSE_27, \ + REVERSE_26, REVERSE_25, REVERSE_24, REVERSE_23, REVERSE_22, REVERSE_21, \ + REVERSE_20, REVERSE_19, REVERSE_18, REVERSE_17, REVERSE_16, REVERSE_15, \ + REVERSE_14, REVERSE_13, REVERSE_12, REVERSE_11, REVERSE_10, REVERSE_09, \ + REVERSE_08, REVERSE_07, REVERSE_06, REVERSE_05, REVERSE_04, REVERSE_03, \ + REVERSE_02, REVERSE_01, REVERSE_00)(__VA_ARGS__) + +#define REVERSE_ARG(...) REVERSE_ARG_(##__VA_ARGS__) + +/* Apply the macro to each argument */ + +#define FOREACH_00(action, count, ...) 0 +#define FOREACH_01(action, count, arg, ...) action(arg, count - 1 ) +#define FOREACH_02(action, count, arg, ...) action(arg, count - 2 ) FOREACH_01(action, count, __VA_ARGS__) +#define FOREACH_03(action, count, arg, ...) action(arg, count - 3 ) FOREACH_02(action, count, __VA_ARGS__) +#define FOREACH_04(action, count, arg, ...) action(arg, count - 4 ) FOREACH_03(action, count, __VA_ARGS__) +#define FOREACH_05(action, count, arg, ...) action(arg, count - 5 ) FOREACH_04(action, count, __VA_ARGS__) +#define FOREACH_06(action, count, arg, ...) action(arg, count - 6 ) FOREACH_05(action, count, __VA_ARGS__) +#define FOREACH_07(action, count, arg, ...) action(arg, count - 7 ) FOREACH_06(action, count, __VA_ARGS__) +#define FOREACH_08(action, count, arg, ...) action(arg, count - 8 ) FOREACH_07(action, count, __VA_ARGS__) +#define FOREACH_09(action, count, arg, ...) action(arg, count - 9 ) FOREACH_08(action, count, __VA_ARGS__) +#define FOREACH_10(action, count, arg, ...) action(arg, count - 10) FOREACH_09(action, count, __VA_ARGS__) +#define FOREACH_11(action, count, arg, ...) action(arg, count - 11) FOREACH_10(action, count, __VA_ARGS__) +#define FOREACH_12(action, count, arg, ...) action(arg, count - 12) FOREACH_11(action, count, __VA_ARGS__) +#define FOREACH_13(action, count, arg, ...) action(arg, count - 13) FOREACH_12(action, count, __VA_ARGS__) +#define FOREACH_14(action, count, arg, ...) action(arg, count - 14) FOREACH_13(action, count, __VA_ARGS__) +#define FOREACH_15(action, count, arg, ...) action(arg, count - 15) FOREACH_14(action, count, __VA_ARGS__) +#define FOREACH_16(action, count, arg, ...) action(arg, count - 16) FOREACH_15(action, count, __VA_ARGS__) +#define FOREACH_17(action, count, arg, ...) action(arg, count - 17) FOREACH_16(action, count, __VA_ARGS__) +#define FOREACH_18(action, count, arg, ...) action(arg, count - 18) FOREACH_17(action, count, __VA_ARGS__) +#define FOREACH_19(action, count, arg, ...) action(arg, count - 19) FOREACH_18(action, count, __VA_ARGS__) +#define FOREACH_20(action, count, arg, ...) action(arg, count - 20) FOREACH_19(action, count, __VA_ARGS__) +#define FOREACH_21(action, count, arg, ...) action(arg, count - 21) FOREACH_20(action, count, __VA_ARGS__) +#define FOREACH_22(action, count, arg, ...) action(arg, count - 22) FOREACH_21(action, count, __VA_ARGS__) +#define FOREACH_23(action, count, arg, ...) action(arg, count - 23) FOREACH_22(action, count, __VA_ARGS__) +#define FOREACH_24(action, count, arg, ...) action(arg, count - 24) FOREACH_23(action, count, __VA_ARGS__) +#define FOREACH_25(action, count, arg, ...) action(arg, count - 25) FOREACH_24(action, count, __VA_ARGS__) +#define FOREACH_26(action, count, arg, ...) action(arg, count - 26) FOREACH_25(action, count, __VA_ARGS__) +#define FOREACH_27(action, count, arg, ...) action(arg, count - 27) FOREACH_26(action, count, __VA_ARGS__) +#define FOREACH_28(action, count, arg, ...) action(arg, count - 28) FOREACH_27(action, count, __VA_ARGS__) +#define FOREACH_29(action, count, arg, ...) action(arg, count - 29) FOREACH_28(action, count, __VA_ARGS__) +#define FOREACH_30(action, count, arg, ...) action(arg, count - 30) FOREACH_29(action, count, __VA_ARGS__) +#define FOREACH_31(action, count, arg, ...) action(arg, count - 31) FOREACH_30(action, count, __VA_ARGS__) +#define FOREACH_32(action, count, arg, ...) action(arg, count - 32) FOREACH_31(action, count, __VA_ARGS__) + +#define FOREACH_ARG_(action, count, ...) \ + GET_ARG_VALUE(0, ##__VA_ARGS__, \ + FOREACH_32, FOREACH_31, FOREACH_30, FOREACH_29, FOREACH_28, FOREACH_27, \ + FOREACH_26, FOREACH_25, FOREACH_24, FOREACH_23, FOREACH_22, FOREACH_21, \ + FOREACH_20, FOREACH_19, FOREACH_18, FOREACH_17, FOREACH_16, FOREACH_15, \ + FOREACH_14, FOREACH_13, FOREACH_12, FOREACH_11, FOREACH_10, FOREACH_09, \ + FOREACH_08, FOREACH_07, FOREACH_06, FOREACH_05, FOREACH_04, FOREACH_03, \ + FOREACH_02, FOREACH_01, FOREACH_00)(action, count, ##__VA_ARGS__) + +#define FOREACH_ARG(action, ...) \ + FOREACH_ARG_(action, GET_ARG_COUNT(__VA_ARGS__), ##__VA_ARGS__) + +#endif /* __INCLUDE_NUTTX_MACRO_H */ + diff --git a/include/nuttx/sched_note.h b/include/nuttx/sched_note.h index 50d587ddb5..305bad308e 100644 --- a/include/nuttx/sched_note.h +++ b/include/nuttx/sched_note.h @@ -32,6 +32,7 @@ #include #include +#include #include #include @@ -125,15 +126,83 @@ # define NOTE_FILTER_TAGMASK_ZERO(s) #endif +/* Printf argument type */ + +#define NOTE_PRINTF_UINT32 0 +#define NOTE_PRINTF_UINT64 1 +#define NOTE_PRINTF_DOUBLE 2 +#define NOTE_PRINTF_STRING 3 + +/* Get/set printf tag. each parameter occupies 2 bits. The highest + * four bits are used to represent the number of parameters, So up to + * 14 variable arguments can be passed. + */ + +#define NOTE_PRINTF_GET_TYPE(tag, index) (((tag) >> (index) * 2) & 0x03) +#define NOTE_PRINTF_GET_COUNT(tag) (((tag) >> 28) & 0x0f) + +/* Check if a variable is 32-bit or 64-bit */ + +#define NOTE_PRINTF_INT_TYPE(arg) (sizeof((arg) + 0) <= sizeof(uint32_t) ? \ + NOTE_PRINTF_UINT32 : NOTE_PRINTF_UINT64) + +/* Use object_size to mark strings of known size */ + +#define NOTE_PRINTF_OBJECT_SIZE(arg) object_size((FAR void *)(uintptr_t)(arg), 2) + +/* Use _Generic to determine the type of the parameter */ + +#define NOTE_PRINTF_ARG_TYPE(__arg__) \ + _Generic((__arg__) + 0, \ + float : NOTE_PRINTF_DOUBLE, \ + double: NOTE_PRINTF_DOUBLE, \ + char *: ({NOTE_PRINTF_OBJECT_SIZE(__arg__) > 0 ? \ + NOTE_PRINTF_STRING : \ + NOTE_PRINTF_INT_TYPE(__arg__);}), \ + const char *: ({NOTE_PRINTF_OBJECT_SIZE(__arg__) > 0 ? \ + NOTE_PRINTF_STRING : \ + NOTE_PRINTF_INT_TYPE(__arg__);}), \ + default: NOTE_PRINTF_INT_TYPE(__arg__)) + +/* Set the type of each parameter */ + +#define NOTE_PRINTF_TYPE(arg, index) + ((NOTE_PRINTF_ARG_TYPE(arg) << (index) * 2)) +#define NOTE_PRINTF_TYPES(...) FOREACH_ARG(NOTE_PRINTF_TYPE, ##__VA_ARGS__) + +/* Using macro expansion to calculate the expression of tag, tag will + * be a constant at compile time, which will reduce the number of + * size in the code. + */ + +#define NOTE_PRINTF_TAG(...) \ + ((GET_ARG_COUNT(__VA_ARGS__) << 28) + NOTE_PRINTF_TYPES(__VA_ARGS__)) + #define SCHED_NOTE_IP \ ({ __label__ __here; __here: (unsigned long)&&__here; }) #define sched_note_event(tag, event, buf, len) \ sched_note_event_ip(tag, SCHED_NOTE_IP, event, buf, len) #define sched_note_vprintf(tag, fmt, va) \ - sched_note_vprintf_ip(tag, SCHED_NOTE_IP, fmt, va) -#define sched_note_printf(tag, fmt, ...) \ - sched_note_printf_ip(tag, SCHED_NOTE_IP, fmt, ##__VA_ARGS__) + sched_note_vprintf_ip(tag, SCHED_NOTE_IP, fmt, 0, va) + +#ifdef CONFIG_DRIVERS_NOTE_STRIP_FORMAT +# define sched_note_printf(tag, fmt, ...) \ + do \ + { \ + static const locate_data(".printf_format") \ + char __fmt__[] = fmt; \ + uint32_t __type__ = NOTE_PRINTF_TAG(__VA_ARGS__); \ + static_assert(GET_ARG_COUNT(__VA_ARGS__) <= 14, \ + "The number of sched_note_nprintf " \ + "parameters needs to be less than 14"); \ + sched_note_printf_ip(tag, SCHED_NOTE_IP, __fmt__, \ + __type__, ##__VA_ARGS__); \ + } \ + while (0) +#else +# define sched_note_printf(tag, fmt, ...) \ + sched_note_printf_ip(tag, SCHED_NOTE_IP, fmt, 0, ##__VA_ARGS__) +#endif #define sched_note_begin(tag) \ sched_note_event(tag, NOTE_DUMP_BEGIN, NULL, 0) @@ -410,6 +479,7 @@ struct note_printf_s struct note_common_s npt_cmn; /* Common note parameters */ uintptr_t npt_ip; /* Instruction pointer called from */ FAR const char *npt_fmt; /* Printf format string */ + uint32_t npt_type; /* Printf parameter type */ char npt_data[1]; /* Print arguments */ }; @@ -585,13 +655,13 @@ void sched_note_heap(uint8_t event, FAR void *heap, FAR void *mem, void sched_note_event_ip(uint32_t tag, uintptr_t ip, uint8_t event, FAR const void *buf, size_t len); void sched_note_vprintf_ip(uint32_t tag, uintptr_t ip, FAR const char *fmt, - va_list va) printf_like(3, 0); -void sched_note_printf_ip(uint32_t tag, uintptr_t ip, - FAR const char *fmt, ...) printf_like(3, 4); + uint32_t type, va_list va) printf_like(3, 0); +void sched_note_printf_ip(uint32_t tag, uintptr_t ip, FAR const char *fmt, + uint32_t type, ...) printf_like(3, 5); #else # define sched_note_event_ip(t,ip,e,b,l) -# define sched_note_vprintf_ip(t,ip,f,v) -# define sched_note_printf_ip(t,ip,f,...) +# define sched_note_vprintf_ip(t,ip,f,p,v) +# define sched_note_printf_ip(t,ip,f,p,...) #endif /* CONFIG_SCHED_INSTRUMENTATION_DUMP */ #if defined(__KERNEL__) || defined(CONFIG_BUILD_FLAT) diff --git a/sched/Kconfig b/sched/Kconfig index be765d9928..2dbbb0a588 100644 --- a/sched/Kconfig +++ b/sched/Kconfig @@ -1307,8 +1307,8 @@ config SCHED_INSTRUMENTATION_DUMP Use note dump for instrumentation. void sched_note_event_ip(uint32_t tag, uintptr_t ip, uint8_t event, FAR const void *buf, size_t len); - void sched_note_vprintf_ip(uint32_t tag, uintptr_t ip, FAR const char *fmt, va_list va) printf_like(3, 0); - void sched_note_printf_ip(uint32_t tag, uintptr_t ip, FAR const char *fmt, ...) printf_like(3, 4); + void sched_note_vprintf_ip(uint32_t tag, uintptr_t ip, FAR const char *fmt, uint32_t type, va_list va) printf_like(3, 0); + void sched_note_printf_ip(uint32_t tag, uintptr_t ip, FAR const char *fmt, uint32_t type, ...) printf_like(3, 5); config SCHED_INSTRUMENTATION_FUNCTION bool "Enable function auto-tracing"