Run compiler on debug macros for type checking
authorSandrine Bailleux <sandrine.bailleux@arm.com>
Wed, 20 Jun 2018 12:50:48 +0000 (14:50 +0200)
committerSandrine Bailleux <sandrine.bailleux@arm.com>
Fri, 13 Jul 2018 09:31:05 +0000 (11:31 +0200)
Even if the log output is too low for a message to be printed out on
the console by the debug macros, it should still be evaluated by the
compiler to get some type checking and validation of the format
specifiers. To do so, introduce the no_tf_log() macro that encloses
the call to tf_log() in an always-false condition.

This avoids the problem of discovering build issues only when we build
the firmware with the right LOG_LEVEL value.

Change-Id: Ic0fd252ab691d0187fd925756a4837aca1cbfd7b
Signed-off-by: Sandrine Bailleux <sandrine.bailleux@arm.com>
include/common/debug.h

index 3f0f84a1ba465fa97db6c4cecfbc82c22cdfb322..99f402c0842e9a37a68d4feebedd015a23913353 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -7,10 +7,12 @@
 #ifndef __DEBUG_H__
 #define __DEBUG_H__
 
-/* The log output macros print output to the console. These macros produce
+/*
+ * The log output macros print output to the console. These macros produce
  * compiled log output only if the LOG_LEVEL defined in the makefile (or the
  * make command line) is greater or equal than the level required for that
  * type of log output.
+ *
  * The format expected is the same as for printf(). For example:
  * INFO("Info %s.\n", "message")    -> INFO:    Info message.
  * WARN("Warning %s.\n", "message") -> WARNING: Warning message.
 #define LOG_MARKER_INFO                        "\x28"  /* 40 */
 #define LOG_MARKER_VERBOSE             "\x32"  /* 50 */
 
+/*
+ * If the log output is too low then this macro is used in place of tf_log()
+ * below. The intent is to get the compiler to evaluate the function call for
+ * type checking and format specifier correctness but let it optimize it out.
+ */
+#define no_tf_log(fmt, ...)                            \
+       do {                                            \
+               if (0) {                                \
+                       tf_log(fmt, ##__VA_ARGS__);     \
+               }                                       \
+       } while (0)
+
 #if LOG_LEVEL >= LOG_LEVEL_NOTICE
 # define NOTICE(...)   tf_log(LOG_MARKER_NOTICE __VA_ARGS__)
 #else
-# define NOTICE(...)
+# define NOTICE(...)   no_tf_log(LOG_MARKER_NOTICE __VA_ARGS__)
 #endif
 
 #if LOG_LEVEL >= LOG_LEVEL_ERROR
 # define ERROR(...)    tf_log(LOG_MARKER_ERROR __VA_ARGS__)
 #else
-# define ERROR(...)
+# define ERROR(...)    no_tf_log(LOG_MARKER_ERROR __VA_ARGS__)
 #endif
 
 #if LOG_LEVEL >= LOG_LEVEL_WARNING
 # define WARN(...)     tf_log(LOG_MARKER_WARNING __VA_ARGS__)
 #else
-# define WARN(...)
+# define WARN(...)     no_tf_log(LOG_MARKER_WARNING __VA_ARGS__)
 #endif
 
 #if LOG_LEVEL >= LOG_LEVEL_INFO
 # define INFO(...)     tf_log(LOG_MARKER_INFO __VA_ARGS__)
 #else
-# define INFO(...)
+# define INFO(...)     no_tf_log(LOG_MARKER_INFO __VA_ARGS__)
 #endif
 
 #if LOG_LEVEL >= LOG_LEVEL_VERBOSE
 # define VERBOSE(...)  tf_log(LOG_MARKER_VERBOSE __VA_ARGS__)
 #else
-# define VERBOSE(...)
+# define VERBOSE(...)  no_tf_log(LOG_MARKER_VERBOSE __VA_ARGS__)
 #endif
 
 void __dead2 do_panic(void);