Skip to content

Instantly share code, notes, and snippets.

@zhuizhuhaomeng
Created July 10, 2023 05:35
Show Gist options
  • Save zhuizhuhaomeng/31c39e579a4aadca06c4c8a7df51c49c to your computer and use it in GitHub Desktop.
Save zhuizhuhaomeng/31c39e579a4aadca06c4c8a7df51c49c to your computer and use it in GitHub Desktop.
commit 1ec33bf603d2900750af2a5c3dc0e964f5dfa4aa
Author: lijunlong <lijunlong@openresty.com>
Date: Mon Jul 10 13:17:46 2023 +0800
Bug: _stp_stack_user_sprint&_stp_stack_kernel_sprint flush the output buffer if the backtrace size greater than STP_BUFFER_SIZE.
diff --git a/runtime/dyninst/print.c b/runtime/dyninst/print.c
index f23c3858e..e2a8b8843 100644
--- a/runtime/dyninst/print.c
+++ b/runtime/dyninst/print.c
@@ -44,7 +44,7 @@ static inline void _stp_print_flush(void)
return;
}
-static void * _stp_reserve_bytes (int numbytes)
+static void * _stp_reserve_bytes (int numbytes, bool *is_sprintf)
{
return _stp_dyninst_transport_reserve_bytes(numbytes);
}
@@ -74,7 +74,7 @@ static void _stp_print_binary (int num, ...)
if (unlikely(num > STP_MAXBINARYARGS))
num = STP_MAXBINARYARGS;
- args = _stp_reserve_bytes(num * sizeof(int64_t));
+ args = _stp_reserve_bytes(num * sizeof(int64_t), NULL);
if (likely(args != NULL)) {
va_start(vargs, num);
@@ -100,7 +100,7 @@ static void _stp_print (const char *str)
static void _stp_print_char (const char c)
{
- char *p = _stp_reserve_bytes(1);;
+ char *p = _stp_reserve_bytes(1, NULL);
if (p) {
*p = c;
diff --git a/runtime/linux/io.c b/runtime/linux/io.c
index 5f7b44a81..c84622b6d 100644
--- a/runtime/linux/io.c
+++ b/runtime/linux/io.c
@@ -63,7 +63,7 @@ static void _stp_vlog (enum code type, const char *func, int line, const char *f
if (!_stp_print_trylock_irqsave(&flags))
return;
- buf = _stp_reserve_bytes(prefix_len + msg_len + 1);
+ buf = _stp_reserve_bytes(prefix_len + msg_len + 1, NULL);
if (!buf)
goto err_unlock;
diff --git a/runtime/linux/print.c b/runtime/linux/print.c
index db71871d2..e7b57cc50 100644
--- a/runtime/linux/print.c
+++ b/runtime/linux/print.c
@@ -40,6 +40,8 @@ struct _stp_log {
char *buf; /* NB we don't use arrays here to avoid allocating memory
on offline CPUs (but still possible ones) */
atomic_t reentrancy_lock;
+ bool no_flush;
+ bool is_full;
};
#include "print_flush.c"
@@ -224,7 +226,7 @@ static inline void _stp_print_flush(void)
/** Reserves space in the output buffer for direct I/O. Must be called with
* _stp_print_trylock_irqsave() held.
*/
-static void * _stp_reserve_bytes (int numbytes)
+static void * _stp_reserve_bytes (int numbytes, bool *is_sprintf)
{
struct _stp_log *log;
char *ret;
@@ -238,6 +240,12 @@ static void * _stp_reserve_bytes (int numbytes)
if (unlikely(numbytes > (STP_BUFFER_SIZE - log->len)))
__stp_print_flush(log);
+ if (is_sprintf != NULL)
+ *is_sprintf = log->no_flush;
+
+ if (log->is_full)
+ return NULL;
+
ret = &log->buf[log->len];
log->len += numbytes;
return ret;
@@ -281,7 +289,7 @@ static void _stp_print_binary (int num, ...)
if (!_stp_print_trylock_irqsave(&flags))
return;
- args = _stp_reserve_bytes(num * sizeof(int64_t));
+ args = _stp_reserve_bytes(num * sizeof(int64_t), NULL);
if (args) {
va_start(vargs, num);
for (i = 0; i < num; i++)
@@ -318,7 +326,7 @@ static void _stp_print (const char *str)
return;
log = per_cpu_ptr(_stp_log_pcpu, raw_smp_processor_id());
- while (1) {
+ while (!log->is_full) {
while (log->len < STP_BUFFER_SIZE && *str)
log->buf[log->len++] = *str++;
if (likely(!*str))
@@ -339,7 +347,10 @@ static void _stp_print_char (const char c)
log = per_cpu_ptr(_stp_log_pcpu, raw_smp_processor_id());
if (unlikely(log->len == STP_BUFFER_SIZE))
__stp_print_flush(log);
- log->buf[log->len++] = c;
+
+ if (likely(!log->no_flush || !log->is_full))
+ log->buf[log->len++] = c;
+
_stp_print_unlock_irqrestore(&flags);
}
diff --git a/runtime/print.h b/runtime/print.h
index ffdea594d..e358532bf 100644
--- a/runtime/print.h
+++ b/runtime/print.h
@@ -15,7 +15,7 @@ static bool _stp_print_trylock_irqsave(unsigned long *flags);
static void _stp_print_unlock_irqrestore(unsigned long *flags);
static int _stp_print_init(void);
static void _stp_print_cleanup(void);
-static void *_stp_reserve_bytes(int numbytes);
+static void *_stp_reserve_bytes(int numbytes, bool *is_sprintf);
static void _stp_unreserve_bytes (int numbytes);
static void _stp_printf(const char *fmt, ...);
static void _stp_print(const char *str);
diff --git a/runtime/print_flush.c b/runtime/print_flush.c
index 98963b3eb..35677b225 100644
--- a/runtime/print_flush.c
+++ b/runtime/print_flush.c
@@ -27,6 +27,12 @@ static void __stp_print_flush(struct _stp_log *log)
/* check to see if there is anything in the buffer */
if (likely(len == 0))
return;
+
+ if (unlikely(log->no_flush)) {
+ log->is_full = true;
+ return;
+ }
+
log->len = 0; /* clear it for later reuse */
dbug_trans(1, "len = %zu\n", len);
diff --git a/runtime/stack.c b/runtime/stack.c
index cdcee4bdd..c5e975acd 100644
--- a/runtime/stack.c
+++ b/runtime/stack.c
@@ -685,6 +685,19 @@ static void _stp_stack_user_print(struct context *c, int sym_flags)
#endif
}
+static void __stp_sprint_begin(struct _stp_log *log)
+{
+ __stp_print_flush(log);
+ log->no_flush = true;
+}
+
+static void __stp_sprint_end(struct _stp_log *log)
+{
+ log->no_flush = false;
+ log->is_full = false;
+ log->len = 0;
+}
+
/** Writes stack backtrace to a string
*
* @param str string
@@ -709,12 +722,12 @@ static void _stp_stack_kernel_sprint(char *str, int size, struct context* c,
}
log = per_cpu_ptr(_stp_log_pcpu, raw_smp_processor_id());
- __stp_print_flush(log);
+ __stp_sprint_begin(log);
_stp_stack_kernel_print(c, sym_flags);
bytes = min_t(int, size - 1, log->len);
memcpy(str, log->buf, bytes);
str[bytes] = '\0';
- log->len = 0;
+ __stp_sprint_end(log);
_stp_print_unlock_irqrestore(&flags);
}
@@ -736,12 +749,12 @@ static void _stp_stack_user_sprint(char *str, int size, struct context* c,
}
log = per_cpu_ptr(_stp_log_pcpu, raw_smp_processor_id());
- __stp_print_flush(log);
+ __stp_sprint_begin(log);
_stp_stack_user_print(c, sym_flags);
bytes = min_t(int, size - 1, log->len);
memcpy(str, log->buf, bytes);
str[bytes] = '\0';
- log->len = 0;
+ __stp_sprint_end(log);
_stp_print_unlock_irqrestore(&flags);
}
diff --git a/runtime/vsprintf.c b/runtime/vsprintf.c
index 606f685e8..98cdac54e 100644
--- a/runtime/vsprintf.c
+++ b/runtime/vsprintf.c
@@ -544,6 +544,7 @@ _stp_vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
int num_bytes = 0;
unsigned long irqflags = 0;
bool got_print_lock = false;
+ bool is_sprintf = false;
/* Reject out-of-range values early */
if (unlikely((int) size < 0))
@@ -728,9 +729,10 @@ _stp_vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
if (!_stp_print_trylock_irqsave(&irqflags))
return 0;
- str = (char*)_stp_reserve_bytes(num_bytes);
+ str = (char*)_stp_reserve_bytes(num_bytes, &is_sprintf);
if (str == NULL) {
- _stp_error("Couldn't reserve any print buffer space\n");
+ if (!is_sprintf)
+ _stp_error("Couldn't reserve any print buffer space\n");
goto err_unlock;
}
got_print_lock = true;
diff --git a/testsuite/systemtap.base/ustack.exp b/testsuite/systemtap.base/ustack.exp
index 30671326a..9604d138f 100644
--- a/testsuite/systemtap.base/ustack.exp
+++ b/testsuite/systemtap.base/ustack.exp
@@ -47,3 +47,25 @@ if {$res ne ""} {
send_log "stderr:\n$stderr"
}
}
+
+# --- TEST 3 ---
+
+set subtest3 "TEST 3: sprint_ubacktrace()"
+
+set res [target_compile ${testpath}/${test}_3.c ./a.out executable \
+ "additional_flags=-O additional_flags=-g additional_flags=-O0"]
+if {$res ne ""} {
+ verbose "target_compile failed: $res" 2
+ fail "$test: $subtest2: unable to compile ${test}_3.c"
+} else {
+ set test_name "$test: $subtest3"
+
+ set cmd "stap -DMAXBACKTRACE=256 --ldd -c ./a.out '$srcdir/$subdir/${test}_3.stp'"
+ set exit_code [run_cmd_2way $cmd out stderr]
+ set out_pat "bt: mark.*"
+ like "${test_name}: stdout" $out $out_pat ""
+ is "${test_name}: exit code" $exit_code 0
+ if {$stderr ne ""} {
+ send_log "stderr:\n$stderr"
+ }
+}
diff --git a/testsuite/systemtap.base/ustack_3.c b/testsuite/systemtap.base/ustack_3.c
new file mode 100644
index 000000000..d159562de
--- /dev/null
+++ b/testsuite/systemtap.base/ustack_3.c
@@ -0,0 +1,22 @@
+void mark()
+{
+}
+
+int my_func_name_is_very_longlonglonglonglonglonglonglonglonglonglong(int depth)
+{
+ int sum;
+
+ if (depth <= 0) {
+ mark();
+ return 0;
+ }
+
+ sum = my_func_name_is_very_longlonglonglonglonglonglonglonglonglonglong(depth - 1);
+ sum += depth;
+ return sum;
+}
+
+int main(void) {
+ my_func_name_is_very_longlonglonglonglonglonglonglonglonglonglong(200);
+ return 0;
+}
diff --git a/testsuite/systemtap.base/ustack_3.stp b/testsuite/systemtap.base/ustack_3.stp
new file mode 100644
index 000000000..01f462ab3
--- /dev/null
+++ b/testsuite/systemtap.base/ustack_3.stp
@@ -0,0 +1,5 @@
+probe process.function("mark") {
+ s = sprint_ubacktrace();
+ s = sprintf("bt: %s", s)
+ printf("%s", s);
+}
diff --git a/translate.cxx b/translate.cxx
index e76fa9f9a..d5769ff28 100644
--- a/translate.cxx
+++ b/translate.cxx
@@ -1459,7 +1459,7 @@ c_unparser::emit_compiled_printfs ()
o->newline() << "num_bytes = clamp(num_bytes, 0, STP_BUFFER_SIZE);";
o->newline() << "if (!_stp_print_trylock_irqsave(&irqflags))";
o->newline(1) << "return;";
- o->newline(-1) << "str = (char*)_stp_reserve_bytes(num_bytes);";
+ o->newline(-1) << "str = (char*)_stp_reserve_bytes(num_bytes, NULL);";
o->newline() << "end = str ? str + num_bytes - 1 : 0;";
}
else // !print_to_stream
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment