From patchwork Thu Apr 14 19:41:33 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Stephen Hemminger X-Patchwork-Id: 109729 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id A2B28A0509; Thu, 14 Apr 2022 21:41:39 +0200 (CEST) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 4384A4067E; Thu, 14 Apr 2022 21:41:39 +0200 (CEST) Received: from mail-pl1-f178.google.com (mail-pl1-f178.google.com [209.85.214.178]) by mails.dpdk.org (Postfix) with ESMTP id 1A1984067C for ; Thu, 14 Apr 2022 21:41:38 +0200 (CEST) Received: by mail-pl1-f178.google.com with SMTP id be5so5486554plb.13 for ; Thu, 14 Apr 2022 12:41:37 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=networkplumber-org.20210112.gappssmtp.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=lrl2kk0pnfddH/AK8cH96JUuHzTSozwSQ2ui8ID7ypY=; b=PoMmGeSTcgXH7PlmAFh2p9n8uGo/LqlL7sK1F9hmCsTW/bUsQ8A1XtRfAUELJCYc+3 R4XPO26Op433KrkD9qwalTXLT9VA/wAMr/3huEQ57KcXjzeD07dQQpbhR/N/Q7Qd9+iJ 1CVQsqWfcjRlb32VpC7QRwtY/n0r17JCYXgbBbhVINhLshQNQompKHSbzEzLtC9Saaan koiLAE2pk0t/gVW/qLUVa82f3cJBb6hf9oRWuxSAP3QkkVzo1iJGpiEjcbu0Gup7XXdr YBAIutc1hUM1OaC26ZH6bOrnojgibe9X8I3SoQKuuR1WWmaDiM8Udso7CQJormKCGJnm 5inw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=lrl2kk0pnfddH/AK8cH96JUuHzTSozwSQ2ui8ID7ypY=; b=Wp8yZanFA3s266+r07hQI/OrHTGssrxpyHHroU5REVC6SLB1GDa4DRl84k4hNeV14K C03DGyxYiEe6sULlbktGqBEIASqEMqZQHrhTdsNTLC3+euVvI+VhHAmJBXXLJVqv4Xp4 n0vIgFlCEMejEZre+sVVZ0eP1J9VFdPMF4SiBnbwquLvKkQ1fBvLwpKxyw4xetVzlrJn I41j9hjZ4bXYQl0Ld7SejSZQPmCKm9F1jV+qQQ1lcmpVGx/CrZ9tuDTAgUCPZV5okP8d wFt7Q7Y01Y26YyYFH5R+guNfbTqfvw8ib+voMCWMQUbzPnKAqvjlQz8ERJFzwRLALKMK sxfA== X-Gm-Message-State: AOAM5300/Rq4jEUzvfjoNu/SdEM5UHfg8b2qB38GKrG+mJVpGN7MEfco 7xYoy9l9vJOvO4ZSButP5laDBRNKvAMkow== X-Google-Smtp-Source: ABdhPJxyjRl/Or8LmNooN1UfwYwa1p3igexKnec75JvpnLBsKFke68tvl7pFsbXyO1qP7cJMpfWa1A== X-Received: by 2002:a17:902:c412:b0:158:642f:bb26 with SMTP id k18-20020a170902c41200b00158642fbb26mr21335459plk.67.1649965296807; Thu, 14 Apr 2022 12:41:36 -0700 (PDT) Received: from hermes.local (204-195-112-199.wavecable.com. [204.195.112.199]) by smtp.gmail.com with ESMTPSA id a15-20020a62e20f000000b00508363eee44sm602598pfi.219.2022.04.14.12.41.35 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 14 Apr 2022 12:41:36 -0700 (PDT) From: Stephen Hemminger To: dev@dpdk.org Cc: Stephen Hemminger , =?utf-8?q?Morten_Br?= =?utf-8?q?=C3=B8rup?= , Bruce Richardson Subject: [PATCH v3] rte_dump_stack: make in async signal safe Date: Thu, 14 Apr 2022 12:41:33 -0700 Message-Id: <20220414194133.244197-1-stephen@networkplumber.org> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220129011039.264377-1-stephen@networkplumber.org> References: <20220129011039.264377-1-stephen@networkplumber.org> MIME-Version: 1.0 X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org rte_dump_stack needs to be usable in situations when a bug is encountered and from signal handlers (such as SEGV). Glibc backtrace_symbols() calls malloc which makes it dangerous in a signal handler that is handling errors that maybe due to memory corruption. Additionally, rte_log() is unsafe because syslog() is not signal safe; printf() is also documented as not being safe. This version formats message and uses writev for each line in a manner similar to what glibc version of backtrace_symbols_fd() does. The FreeBSD version of backtrace_symbols_fd() is not signal safe. Sample output: 0: ./build/app/dpdk-testpmd (rte_dump_stack+0x2b) [560a6e9c002b] 1: ./build/app/dpdk-testpmd (main+0xad) [560a6decd5ad] 2: /lib/x86_64-linux-gnu/libc.so.6 (__libc_start_main+0xcd) [7fd43d3e27fd] 3: ./build/app/dpdk-testpmd (_start+0x2a) [560a6e83628a] Bugzilla ID: 929 Acked-by: Morten Brørup Signed-off-by: Stephen Hemminger --- v3 - merge previous two patches into one common Linux/FreeBSD code. - rewrite the code to not use functions which are not documented to be signal safe. lib/eal/freebsd/eal_debug.c | 43 ------------- lib/eal/freebsd/meson.build | 1 - lib/eal/include/rte_debug.h | 2 +- lib/eal/linux/eal_debug.c | 38 ----------- lib/eal/linux/meson.build | 1 - lib/eal/unix/eal_debug.c | 123 ++++++++++++++++++++++++++++++++++++ lib/eal/unix/meson.build | 1 + 7 files changed, 125 insertions(+), 84 deletions(-) delete mode 100644 lib/eal/freebsd/eal_debug.c delete mode 100644 lib/eal/linux/eal_debug.c create mode 100644 lib/eal/unix/eal_debug.c diff --git a/lib/eal/freebsd/eal_debug.c b/lib/eal/freebsd/eal_debug.c deleted file mode 100644 index 64dab4e0da24..000000000000 --- a/lib/eal/freebsd/eal_debug.c +++ /dev/null @@ -1,43 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#ifdef RTE_BACKTRACE -#include -#endif -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#define BACKTRACE_SIZE 256 - -/* dump the stack of the calling core */ -void rte_dump_stack(void) -{ -#ifdef RTE_BACKTRACE - void *func[BACKTRACE_SIZE]; - char **symb = NULL; - int size; - - size = backtrace(func, BACKTRACE_SIZE); - symb = backtrace_symbols(func, size); - - if (symb == NULL) - return; - - while (size > 0) { - rte_log(RTE_LOG_ERR, RTE_LOGTYPE_EAL, - "%d: [%s]\n", size, symb[size - 1]); - size --; - } - - free(symb); -#endif /* RTE_BACKTRACE */ -} diff --git a/lib/eal/freebsd/meson.build b/lib/eal/freebsd/meson.build index 398ceab71d03..85cca5a096ca 100644 --- a/lib/eal/freebsd/meson.build +++ b/lib/eal/freebsd/meson.build @@ -7,7 +7,6 @@ sources += files( 'eal.c', 'eal_alarm.c', 'eal_cpuflags.c', - 'eal_debug.c', 'eal_dev.c', 'eal_hugepage_info.c', 'eal_interrupts.c', diff --git a/lib/eal/include/rte_debug.h b/lib/eal/include/rte_debug.h index c4bc71ce28f5..2c4b94a7c9bf 100644 --- a/lib/eal/include/rte_debug.h +++ b/lib/eal/include/rte_debug.h @@ -22,7 +22,7 @@ extern "C" { #endif /** - * Dump the stack of the calling core to the console. + * Dump the stack of the calling core to the standard error. */ void rte_dump_stack(void); diff --git a/lib/eal/linux/eal_debug.c b/lib/eal/linux/eal_debug.c deleted file mode 100644 index b0ecf5a9dcde..000000000000 --- a/lib/eal/linux/eal_debug.c +++ /dev/null @@ -1,38 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2014 Intel Corporation - */ - -#ifdef RTE_BACKTRACE -#include -#endif -#include -#include - -#include -#include - -#define BACKTRACE_SIZE 256 - -/* dump the stack of the calling core */ -void rte_dump_stack(void) -{ -#ifdef RTE_BACKTRACE - void *func[BACKTRACE_SIZE]; - char **symb = NULL; - int size; - - size = backtrace(func, BACKTRACE_SIZE); - symb = backtrace_symbols(func, size); - - if (symb == NULL) - return; - - while (size > 0) { - rte_log(RTE_LOG_ERR, RTE_LOGTYPE_EAL, - "%d: [%s]\n", size, symb[size - 1]); - size --; - } - - free(symb); -#endif /* RTE_BACKTRACE */ -} diff --git a/lib/eal/linux/meson.build b/lib/eal/linux/meson.build index 65f2ac6b4798..3cccfa36c0a4 100644 --- a/lib/eal/linux/meson.build +++ b/lib/eal/linux/meson.build @@ -7,7 +7,6 @@ sources += files( 'eal.c', 'eal_alarm.c', 'eal_cpuflags.c', - 'eal_debug.c', 'eal_dev.c', 'eal_hugepage_info.c', 'eal_interrupts.c', diff --git a/lib/eal/unix/eal_debug.c b/lib/eal/unix/eal_debug.c new file mode 100644 index 000000000000..79b6f2fea2b9 --- /dev/null +++ b/lib/eal/unix/eal_debug.c @@ -0,0 +1,123 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2014 Intel Corporation + */ + +#include + + +#ifdef RTE_BACKTRACE + +#include +#include +#include +#include +#include + +#define BACKTRACE_SIZE 256 + +/* + * Convert number to string and return start of string. + * Note: string does not start at beginning of buffer. + */ +static char *safe_itoa(long val, char *buf, size_t len, unsigned int radix) +{ + char *bp = buf + len; + static const char hexdigit[] = "0123456789abcdef"; + + *--bp = '\0'; /* Null terminate the string */ + do { + /* if buffer is not big enough, then truncate */ + if (bp == buf) + return bp; + + *--bp = hexdigit[val % radix]; + val /= radix; + } while (val != 0); + + return bp; +} + + +/* Dump the stack of the calling core + * + * To be safe in signal handler requires limiting what functions are + * used in this code since may be called from inside libc or + * when malloc poll is corrupt. + * + * Most of libc is therefore not safe, include RTE_LOG (calls syslog); + * backtrace_symbols (calls malloc), etc. + */ +void rte_dump_stack(void) +{ + void *func[BACKTRACE_SIZE]; + Dl_info info; + char buf1[8], buf2[32], buf3[32], buf4[32]; + struct iovec iov[10]; + int i, size; + + size = backtrace(func, BACKTRACE_SIZE); + + for (i = 0; i < size; i++) { + struct iovec *io = iov; + char *str; + uintptr_t base; + long offset; + void *pc = func[i]; + +/* Macro to put string onto set of iovecs + * cast is to suppress warnings about lose of const qualifier + */ +#define PUSH_IOV(io, str) { \ + (io)->iov_base = (char *)(uintptr_t)str; \ + (io)->iov_len = strlen(str); \ + ++io; } + + /* output stack frame number */ + str = safe_itoa(i, buf1, sizeof(buf1), 10); + PUSH_IOV(io, str); /* iov[0] */ + PUSH_IOV(io, ": "); /* iov[1] */ + + /* Lookup the symbol information */ + if (dladdr (pc, &info) == 0) { + PUSH_IOV(io, "?? ["); + } else { + const char *fname; + + if (info.dli_fname && *info.dli_fname) + fname = info.dli_fname; + else + fname = "(vdso)"; + PUSH_IOV(io, fname); /* iov[2] */ + PUSH_IOV(io, " ("); /* iov[3] */ + + if (info.dli_saddr != NULL) { + PUSH_IOV(io, info.dli_sname); /* iov[4] */ + base = (uintptr_t)info.dli_saddr; + } else { + str = safe_itoa((unsigned long)info.dli_fbase, + buf3, sizeof(buf3), 16); + PUSH_IOV(io, str); + base = (uintptr_t)info.dli_fbase; + } + + PUSH_IOV(io, "+0x"); /* iov[5] */ + + offset = (uintptr_t)pc - base; + str = safe_itoa(offset, buf4, sizeof(buf4), 16); + PUSH_IOV(io, str); /* iov[6] */ + + PUSH_IOV(io, ") ["); /* iov[7] */ + } + + str = safe_itoa((unsigned long)pc, buf2, sizeof(buf2), 16); + PUSH_IOV(io, str); /* iov[8] */ + PUSH_IOV(io, "]\n"); /* iov[9] */ + + if (writev(STDERR_FILENO, iov, io - iov) < 0) + break; + } +} +#else +/* stub if not enabled */ +void rte_dump_stack(void) { } +#endif /* RTE_BACKTRACE */ diff --git a/lib/eal/unix/meson.build b/lib/eal/unix/meson.build index a22ea7cabc46..9c59f3d31693 100644 --- a/lib/eal/unix/meson.build +++ b/lib/eal/unix/meson.build @@ -2,6 +2,7 @@ # Copyright(c) 2020 Dmitry Kozlyuk sources += files( + 'eal_debug.c', 'eal_file.c', 'eal_unix_memory.c', 'eal_unix_timer.c',