mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-23 17:30:02 +00:00
![Jason Baron](/assets/img/avatar_default.png)
Although dynamic debug is often only used for debug builds, sometimes its enabled for production builds as well. Minimize its impact by using jump labels. This reduces the text section by 7000+ bytes in the kernel image below. It does increase data, but this should only be referenced when changing the direction of the branches, and hence usually not in cache. text data bss dec hex filename 8194852 4879776 925696 14000324 d5a0c4 vmlinux.pre 8187337 4960224 925696 14073257 d6bda9 vmlinux.post Link: http://lkml.kernel.org/r/d165b465e8c89bc582d973758d40be44c33f018b.1467837322.git.jbaron@akamai.com Signed-off-by: Jason Baron <jbaron@akamai.com> Cc: "David S. Miller" <davem@davemloft.net> Cc: Arnd Bergmann <arnd@arndb.de> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> Cc: Chris Metcalf <cmetcalf@mellanox.com> Cc: Heiko Carstens <heiko.carstens@de.ibm.com> Cc: Joe Perches <joe@perches.com> Cc: Martin Schwidefsky <schwidefsky@de.ibm.com> Cc: Michael Ellerman <mpe@ellerman.id.au> Cc: Paul Mackerras <paulus@samba.org> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
185 lines
5 KiB
C
185 lines
5 KiB
C
#ifndef _DYNAMIC_DEBUG_H
|
|
#define _DYNAMIC_DEBUG_H
|
|
|
|
#if defined(CC_HAVE_ASM_GOTO) && defined(CONFIG_JUMP_LABEL)
|
|
#include <linux/jump_label.h>
|
|
#endif
|
|
|
|
/*
|
|
* An instance of this structure is created in a special
|
|
* ELF section at every dynamic debug callsite. At runtime,
|
|
* the special section is treated as an array of these.
|
|
*/
|
|
struct _ddebug {
|
|
/*
|
|
* These fields are used to drive the user interface
|
|
* for selecting and displaying debug callsites.
|
|
*/
|
|
const char *modname;
|
|
const char *function;
|
|
const char *filename;
|
|
const char *format;
|
|
unsigned int lineno:18;
|
|
/*
|
|
* The flags field controls the behaviour at the callsite.
|
|
* The bits here are changed dynamically when the user
|
|
* writes commands to <debugfs>/dynamic_debug/control
|
|
*/
|
|
#define _DPRINTK_FLAGS_NONE 0
|
|
#define _DPRINTK_FLAGS_PRINT (1<<0) /* printk() a message using the format */
|
|
#define _DPRINTK_FLAGS_INCL_MODNAME (1<<1)
|
|
#define _DPRINTK_FLAGS_INCL_FUNCNAME (1<<2)
|
|
#define _DPRINTK_FLAGS_INCL_LINENO (1<<3)
|
|
#define _DPRINTK_FLAGS_INCL_TID (1<<4)
|
|
#if defined DEBUG
|
|
#define _DPRINTK_FLAGS_DEFAULT _DPRINTK_FLAGS_PRINT
|
|
#else
|
|
#define _DPRINTK_FLAGS_DEFAULT 0
|
|
#endif
|
|
unsigned int flags:8;
|
|
#ifdef HAVE_JUMP_LABEL
|
|
union {
|
|
struct static_key_true dd_key_true;
|
|
struct static_key_false dd_key_false;
|
|
} key;
|
|
#endif
|
|
} __attribute__((aligned(8)));
|
|
|
|
|
|
int ddebug_add_module(struct _ddebug *tab, unsigned int n,
|
|
const char *modname);
|
|
|
|
#if defined(CONFIG_DYNAMIC_DEBUG)
|
|
extern int ddebug_remove_module(const char *mod_name);
|
|
extern __printf(2, 3)
|
|
void __dynamic_pr_debug(struct _ddebug *descriptor, const char *fmt, ...);
|
|
|
|
extern int ddebug_dyndbg_module_param_cb(char *param, char *val,
|
|
const char *modname);
|
|
|
|
struct device;
|
|
|
|
extern __printf(3, 4)
|
|
void __dynamic_dev_dbg(struct _ddebug *descriptor, const struct device *dev,
|
|
const char *fmt, ...);
|
|
|
|
struct net_device;
|
|
|
|
extern __printf(3, 4)
|
|
void __dynamic_netdev_dbg(struct _ddebug *descriptor,
|
|
const struct net_device *dev,
|
|
const char *fmt, ...);
|
|
|
|
#define DEFINE_DYNAMIC_DEBUG_METADATA_KEY(name, fmt, key, init) \
|
|
static struct _ddebug __aligned(8) \
|
|
__attribute__((section("__verbose"))) name = { \
|
|
.modname = KBUILD_MODNAME, \
|
|
.function = __func__, \
|
|
.filename = __FILE__, \
|
|
.format = (fmt), \
|
|
.lineno = __LINE__, \
|
|
.flags = _DPRINTK_FLAGS_DEFAULT, \
|
|
dd_key_init(key, init) \
|
|
}
|
|
|
|
#ifdef HAVE_JUMP_LABEL
|
|
|
|
#define dd_key_init(key, init) key = (init)
|
|
|
|
#ifdef DEBUG
|
|
#define DEFINE_DYNAMIC_DEBUG_METADATA(name, fmt) \
|
|
DEFINE_DYNAMIC_DEBUG_METADATA_KEY(name, fmt, .key.dd_key_true, \
|
|
(STATIC_KEY_TRUE_INIT))
|
|
|
|
#define DYNAMIC_DEBUG_BRANCH(descriptor) \
|
|
static_branch_likely(&descriptor.key.dd_key_true)
|
|
#else
|
|
#define DEFINE_DYNAMIC_DEBUG_METADATA(name, fmt) \
|
|
DEFINE_DYNAMIC_DEBUG_METADATA_KEY(name, fmt, .key.dd_key_false, \
|
|
(STATIC_KEY_FALSE_INIT))
|
|
|
|
#define DYNAMIC_DEBUG_BRANCH(descriptor) \
|
|
static_branch_unlikely(&descriptor.key.dd_key_false)
|
|
#endif
|
|
|
|
#else
|
|
|
|
#define dd_key_init(key, init)
|
|
|
|
#define DEFINE_DYNAMIC_DEBUG_METADATA(name, fmt) \
|
|
DEFINE_DYNAMIC_DEBUG_METADATA_KEY(name, fmt, 0, 0)
|
|
|
|
#ifdef DEBUG
|
|
#define DYNAMIC_DEBUG_BRANCH(descriptor) \
|
|
likely(descriptor.flags & _DPRINTK_FLAGS_PRINT)
|
|
#else
|
|
#define DYNAMIC_DEBUG_BRANCH(descriptor) \
|
|
unlikely(descriptor.flags & _DPRINTK_FLAGS_PRINT)
|
|
#endif
|
|
|
|
#endif
|
|
|
|
#define dynamic_pr_debug(fmt, ...) \
|
|
do { \
|
|
DEFINE_DYNAMIC_DEBUG_METADATA(descriptor, fmt); \
|
|
if (DYNAMIC_DEBUG_BRANCH(descriptor)) \
|
|
__dynamic_pr_debug(&descriptor, pr_fmt(fmt), \
|
|
##__VA_ARGS__); \
|
|
} while (0)
|
|
|
|
#define dynamic_dev_dbg(dev, fmt, ...) \
|
|
do { \
|
|
DEFINE_DYNAMIC_DEBUG_METADATA(descriptor, fmt); \
|
|
if (DYNAMIC_DEBUG_BRANCH(descriptor)) \
|
|
__dynamic_dev_dbg(&descriptor, dev, fmt, \
|
|
##__VA_ARGS__); \
|
|
} while (0)
|
|
|
|
#define dynamic_netdev_dbg(dev, fmt, ...) \
|
|
do { \
|
|
DEFINE_DYNAMIC_DEBUG_METADATA(descriptor, fmt); \
|
|
if (DYNAMIC_DEBUG_BRANCH(descriptor)) \
|
|
__dynamic_netdev_dbg(&descriptor, dev, fmt, \
|
|
##__VA_ARGS__); \
|
|
} while (0)
|
|
|
|
#define dynamic_hex_dump(prefix_str, prefix_type, rowsize, \
|
|
groupsize, buf, len, ascii) \
|
|
do { \
|
|
DEFINE_DYNAMIC_DEBUG_METADATA(descriptor, \
|
|
__builtin_constant_p(prefix_str) ? prefix_str : "hexdump");\
|
|
if (DYNAMIC_DEBUG_BRANCH(descriptor)) \
|
|
print_hex_dump(KERN_DEBUG, prefix_str, \
|
|
prefix_type, rowsize, groupsize, \
|
|
buf, len, ascii); \
|
|
} while (0)
|
|
|
|
#else
|
|
|
|
#include <linux/string.h>
|
|
#include <linux/errno.h>
|
|
|
|
static inline int ddebug_remove_module(const char *mod)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static inline int ddebug_dyndbg_module_param_cb(char *param, char *val,
|
|
const char *modname)
|
|
{
|
|
if (strstr(param, "dyndbg")) {
|
|
/* avoid pr_warn(), which wants pr_fmt() fully defined */
|
|
printk(KERN_WARNING "dyndbg param is supported only in "
|
|
"CONFIG_DYNAMIC_DEBUG builds\n");
|
|
return 0; /* allow and ignore */
|
|
}
|
|
return -EINVAL;
|
|
}
|
|
|
|
#define dynamic_pr_debug(fmt, ...) \
|
|
do { if (0) printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__); } while (0)
|
|
#define dynamic_dev_dbg(dev, fmt, ...) \
|
|
do { if (0) dev_printk(KERN_DEBUG, dev, fmt, ##__VA_ARGS__); } while (0)
|
|
#endif
|
|
|
|
#endif
|