Created
July 10, 2023 05:35
-
-
Save zhuizhuhaomeng/31c39e579a4aadca06c4c8a7df51c49c to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
commit 1ec33bf603d2900750af2a5c3dc0e964f5dfa4aa | |
Author: lijunlong <[email protected]> | |
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