-
Notifications
You must be signed in to change notification settings - Fork 479
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
arch/riscv64: Add basic mcount tracing support for RISC-V 64bit #1815
Conversation
If you are interested in doing basic tracing with the mcount function in a RISC-V environment, please see the branch at the link below. |
I tried basic tracing on RISC-V with your implementation, The result of basic test is below. sm_ple38@starfive:~/uftrace$ ./uftrace --libmcount-path=. -v --no-libcall t-abc
uftrace: running uftrace ( riscv64 dwarf python3 tui perf sched dynamic )
uftrace: checking binary t-abc
uftrace: skipping perf event due to error: Function not implemented
uftrace: creating 1 thread(s) for recording
uftrace: using ./libmcount/libmcount.so library for tracing
mcount: initializing mcount library
mcount: mcount setup done
mcount: new session started: 51b82f567d330d82: t-abc
mcount: mcount trace finished
mcount: exit from libmcount
uftrace: child terminated with exit code: 8
uftrace: reading /tmp/uftrace-live-iGLq3T/task.txt file
uftrace: flushing /uftrace-51b82f567d330d82-234695-000
uftrace: live-record finished..
uftrace: start live-replaying...
uftrace: reading /tmp/uftrace-live-iGLq3T/task.txt file
fstack: fixup for some special functions
uftrace: add field "duration"
uftrace: add field "tid"
# DURATION TID FUNCTION
[234695] | main() {
[234695] | a() {
[234695] | b() {
5.250 us [234695] | c();
14.000 us [234695] | } /* b */
17.500 us [234695] | } /* a */
23.251 us [234695] | } /* main */
uftrace: removing /tmp/uftrace-live-iGLq3T directory Thank you so much for making uftrace usable |
In my opinion, |
Thanks for the good point @SEOKMIN83. I had forgotten the part about needing a way to run this. Currently, this task can be executed as follows after building from the root directory of the uftrace source code.
|
Thank you |
I believe the diff --git a/arch/riscv64/mcount.S b/arch/riscv64/mcount.S
index 91d677bb..498f38e0 100644
--- a/arch/riscv64/mcount.S
+++ b/arch/riscv64/mcount.S
@@ -59,20 +59,12 @@ ENTRY(mcount_return)
sd fp, 8(sp)
addi fp, sp, 24
/* save return values */
sd a0, 0(sp)
/* set the first argument of mcount_exit as pointer to return values */
addi a0, sp, 0
/* call mcount_exit func */
call mcount_exit
- mv t1, a0
-
- /* restore return values */
- ld a0, 0(sp)
-
/* restore frame pointer */
ld s0, 8(sp)
ld ra, 16(sp)
@@ -80,5 +72,5 @@ ENTRY(mcount_return)
addi sp, sp, 24
/* call return address */
- jr t1
+ jr a0
END(mcount_return) If you try this code and see any issues, please let me know in the comments. |
1b13502
to
8ebbaf4
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In d8ad79e arch/riscv64: Update 'mcount.S' to support tracking based on mcount func
,
Info : When compiling the target program with gcc, you need to add
'-O0' or add '-fno-omit-frame-pointer' as an option because it will
disable frame pointers when optimization options are enabled.
Users do not have to specify -O0
because it is the default setting. You better explain it as follows.
In order to figure out the address of parent_loc, we need the frame pointer,
but compiler optimization such as `-O2` in gcc removes the `fp` so we won't
be able know where to change to hijack the return address to `mcount_return`.
This problem only happens in gcc, but not in clang.
To avoid the problem, `-fno-omit-frame-pointer` must be used when gcc
optimization option is used in riscv64.
In addition, we better have the following change in this PR.
diff --git a/uftrace.c b/uftrace.c
index 69e6cefc..69486e94 100644
--- a/uftrace.c
+++ b/uftrace.c
@@ -1389,7 +1389,10 @@ int main(int argc, char *argv[])
struct uftrace_opts opts = {
.mode = UFTRACE_MODE_INVALID,
.dirname = UFTRACE_DIR_NAME,
+#if !defined(__riscv)
+ /* FIXME: disable libcall until PLT hooking is implemented in riscv64. */
.libcall = true,
+#endif
.bufsize = SHMEM_BUFFER_SIZE,
.max_stack = OPT_RSTACK_DEFAULT,
.port = UFTRACE_RECV_PORT,
This is needed to avoid segfault when --no-libcall
is not used.
It looks the argument handling is incorrect even for integer types for now.
The return address of |
I will update the commit to incorporate your feedback. Also, the argument handling issue has been confirmed in my environment and seems to be related to the mcount_return part, which I recently removed as unnecessary. As such, I will be reverting that code back. |
8ebbaf4
to
b3df19d
Compare
And I was able to see the following results after the patch. Thanks to this, we no longer need to use the
|
It works well. !!!!! sm_ple38@starfive:~/uftrace$ gcc -pg -g tests/s-abc.c -o t-abc
sm_ple38@starfive:~/uftrace$ ./uftrace --libmcount-path=. -a t-abc
# DURATION TID FUNCTION
[285395] | main(0x3f8ba48808, 0x3fe94d3338) {
[285395] | a() {
[285395] | b() {
1.750 us [285395] | c() = 85395;
6.000 us [285395] | } = 85396; /* b */
7.250 us [285395] | } = 85395; /* a */
12.750 us [285395] | } = 0; /* main */ |
If it is a string, it will not work.
$ ./uftrace -a t-arg
# DURATION TID FUNCTION
0.691 us [224359] | __monstartup();
0.140 us [224359] | __cxa_atexit();
[224359] | main(1, 0x7fff378d7338) {
[224359] | foo(3) {
[224359] | bar(2, "c") {
0.561 us [224359] | strcmp("c", "c") = 0;
184.333 us [224359] | } = 0; /* bar */
[224359] | bar(1, "b") {
0.220 us [224359] | strcmp("b", "b") = 0;
0.872 us [224359] | } = 0; /* bar */
[224359] | bar(0, "a") {
0.190 us [224359] | strcmp("a", "a") = 0;
0.682 us [224359] | } = 0; /* bar */
187.098 us [224359] | } = 0; /* foo */
0.270 us [224359] | many(12) = 0;
[224359] | pass(3) {
0.531 us [224359] | check(big{...}, 0x7fff378d7190) = 0;
1.082 us [224359] | } = 0; /* pass */
190.775 us [224359] | } = 0; /* main */
$ ./uftrace -a t-arg
# DURATION TID FUNCTION
[286418] | main(1, 0x3ff0657448) {
[286418] | foo(3) {
2.501 us [286418] | bar(2, 68944) = 0;
0.500 us [286418] | bar(1, 68942) = 0;
0.500 us [286418] | bar(0, 68940) = 0;
10.001 us [286418] | } = 0; /* foo */
1.250 us [286418] | many(12) = 0;
[286418] | pass(3) {
1.250 us [286418] | check(big{...}, 0x3ff0657200) = 0;
4.250 us [286418] | } = 0; /* pass */
21.501 us [286418] | } = 0; /* main */ Also, if you change the order of the arguments in the bar() function, the result is the same. $ ./uftrace -a t-arg2
# DURATION TID FUNCTION
[287700] | main(1, 0x3fd905b438) {
[287700] | foo(3) {
3.000 us [287700] | bar(68944, 2) = 0;
0.750 us [287700] | bar(68942, 1) = 0;
0.750 us [287700] | bar(68940, 0) = 0;
10.750 us [287700] | } = 0; /* foo */
1.000 us [287700] | many(12) = 0;
[287700] | pass(3) {
1.500 us [287700] | check(big{...}, 0x3fd905b1f0) = 0;
4.750 us [287700] | } = 0; /* pass */
24.000 us [287700] | } = 0; /* main */ |
Hmm... I found the same problem on RISC-V and tested characters and strings.
In the ASCII code table, the decimal 99 corresponds to 'c', and debugging result that the value of the string argument to the So I'm guessing it's a matter of the code below in /* utils/dwarf.c */
931: if (td->pointer) {
932: td->size = sizeof(long) * 8;
933:
934: /* treat 'char *' as string */
935: if (td->pointer == 1 && tname && !strcmp(tname, "char"))
936: td->fmt = ARG_FMT_STR;
937: else
938: td->fmt = ARG_FMT_PTR;
939: return true;
940: } |
Like you said |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I get the following error when running it in debug build.
$ uftrace record -a a.out
/home/user/uftrace/utils/regs.c:437: arch_register_dwarf_name: ASSERT `arch < ARRAY_SIZE(arch_dwarf_tables)' failed.
Stack trace:
#1 0x003fb30d3ca2 stacktrace + 0x34
Please report this bug to https://github.com/namhyung/uftrace/issues.
WARN: child terminated by signal: 5: Trace/breakpoint trap
Attaching gdb shows backtrace info as follows.
(gdb) r
...
/home/user/uftrace/utils/regs.c:437: arch_register_dwarf_name: ASSERT `arch < ARRAY_SIZE(arch_dwarf_tables)' failed.
Stack trace:
#1 0x003ff7fbaca2 stacktrace + 0x34
Please report this bug to https://github.com/namhyung/uftrace/issues.
Thread 2.1 "a.out" received signal SIGTRAP, Trace/breakpoint trap.
[Switching to Thread 0x3ff7ac9010 (LWP 290922)]
__GI_raise (sig=<optimized out>) at ../sysdeps/unix/sysv/linux/raise.c:49
49 in ../sysdeps/unix/sysv/linux/raise.c
(gdb) bt
#0 __GI_raise (sig=<optimized out>) at ../sysdeps/unix/sysv/linux/raise.c:49
#1 0x0000003ff7fb0092 in arch_register_dwarf_name (arch=UFT_CPU_RISCV64, dwarf_reg=90) at /home/user/uftrace/utils/regs.c:437
#2 0x0000003ff7fc1456 in add_location (spec=0x3fffffea10 "arg1", len=256, die=0x3fffffeb18, ad=0x3fffffeb80)
at /home/user/uftrace/utils/dwarf.c:1184
#3 0x0000003ff7fc185e in get_argspec (die=0x3fffffec98, data=0x3fffffeb80) at /home/user/uftrace/utils/dwarf.c:1290
#4 0x0000003ff7fc1fec in get_dwarfspecs_cb (die=0x3fffffec98, data=0x3fffffee10) at /home/user/uftrace/utils/dwarf.c:1512
#5 0x0000003ff7c348b8 in ?? () from /usr/lib/riscv64-linux-gnu/libdw.so.1
It looks you need to implement utf_riscv64_dwarf_table
at https://github.com/namhyung/uftrace/blob/v0.14/utils/regs.c#L415-L421.
static const struct uftrace_reg_table *arch_dwarf_tables[] = {
NULL,
uft_x86_64_dwarf_table,
uft_arm_dwarf_table,
uft_aarch64_dwarf_table,
uft_i386_dwarf_table,
};
arch/riscv64/mcount-support.c
Outdated
default: | ||
return -1; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My compiler complains this part as follows.
/home/user/uftrace/arch/riscv64/mcount-support.c: In function 'mcount_get_register_arg':
/home/user/uftrace/arch/riscv64/mcount-support.c:82:1: error: control reaches end of non-void function [-Werror=return-type]
82 | }
| ^
cc1: all warnings being treated as errors
You better remove default
case, then move return -1
to the end of this function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also got an error message after the make DEBUG=1
debug build, which looked like it needed fixing.
Your suggestion is good, but mcount-support.c
in other architectures uses return 0;
.
This was my mistake during the porting process and I think adding return 0;
is a good way to be consistent, so I will apply the same method as the other architectures.
I was referring to the psABI documentation for RISC-V to implement the DWARF-specific code that was the feedback regarding the Argument Handling feature. However, I've realized that the list of changes to be made is longer than I thought and that I need to reorder the previous commits to make this work. Therefore, I reordered the commits and made the modifications in the I followed the problem backwards using /home/test/workdir/uftrace/arch/riscv64/mcount-support.c:18:13: error: 'mcount_get_struct_arg' defined but not used [-Werror=unused-function].
18 | static void mcount_get_struct_arg(struct mcount_arg_context *ctx, struct uftrace_arg_spec *spec)
| ^~~~~~~~~~~~~~~~~~~~~
/home/test/workdir/uftrace/arch/riscv64/mcount-support.c:13:13: error: 'mcount_get_stack_arg' defined but not used [-Werror=unused-function].
13 | static void mcount_get_stack_arg(struct mcount_arg_context *ctx, struct uftrace_arg_spec *spec)
| ^~~~~~~~~~~~~~~~~~~~
/home/test/workdir/uftrace/arch/riscv64/mcount-support.c:8:12: error: 'mcount_get_register_arg' defined but not used [-Werror=unused-function].
8 | static int mcount_get_register_arg(struct mcount_arg_context *ctx, struct uftrace_arg_spec *spec)
| ^~~~~~~~~~~~~~~~~~~~~~~
|
I think we can merge the basic RISC-V support code first without argument handling. The new architecture support is not a simple task, we can approach it step by step. You may want to file a separate issue for the arguments and return value tracing. |
Thanks for the feedback @namhyung I will leave only the basic RISC-V support code in the current PR and create a new PR for the argument handling. However, when I built the first commit for RISC-V porting using the Therefore, I will verify the commits related to the basic RISC-V Support code using both commands and if everything is fine, I will re-upload the commits to the current PR. |
d1d24a7
to
0ed96e9
Compare
The unittest is a separate binary including all the code but with a different main function. Some test codes are in the |
I have investigated the unittest and found that it doesn't work only in gcc. Switching the compiler to clang makes it work fine. You can manually modify
The reason looks the 1. gcc built
2. clang built
@gichoel It looks a bug in gcc on riscv so I think you can ignore this issue. I think clang better supports RISC-V for our purpose because of multiple reasons. clang doesn't have the following problems that gcc have.
Let's focus on clang support for RISC-V as of now. |
As you confirmed, switching to clang has resulted in all test cases working fine except for one skip. (The skip occurs in the same test case on x86_64). All future RISC-V porting work will be done with clang as you suggested. Thanks. |
I'm ok with proceeding for clang, but could you please share more details of the GCC problems? Specially I'd like to see the actual |
The results of your requested Additionally, these results were run on a RISC-V board. 1.
2.
|
umm... In the last discussion, we discussed an issue with the execution of the I don't see anything further mentioned in that PR, so I'm curious. PS : I've been working on researching and analyzing material for a porting of the So if more testing is needed or there are additional issues, there's no need to rush this PR. |
Sorry I didn't follow the development lately and thought there are more remaining issues. The test failures on GCC are unfortunate but as long as it works on clang, there's should be no fundamental problems. I'm more concerning about the PLT problems and looking forward to seeing a solution soon. If @honggyukim is ok, I can merge this. |
Sorry @gichoel, we missed further discussion after going into the unittest topic. I'm okay for almost most of the implementation. But I just found that the floating point argument handling is broken. You can reproduce the problem as follows. $ ./runtest.py -vdp -O0 -c clang 083
...
t083_arg_float: diff result of clang -pg -O0
--- expect 2023-10-05 13:19:42.213047344 +0000
+++ result 2023-10-05 13:19:42.213047344 +0000
@@ -1,6 +1,6 @@
main() {
- float_add(-0.100000, 0.200000) = 0.100000;
- float_sub(0.100000, 0.200000) = -0.100000;
- float_mul(300.000000, 400.000000) = 120000.000000;
- float_div(40000000000.000000, -0.020000) = -2000000000000.000000;
+ float_add(-0.100000, 0.200000) = nan;
+ float_sub(0.100000, 0.200000) = nan;
+ float_mul(300.000000, 400.000000) = 0.000000;
+ float_div(40000000000.000000, -0.020000) = 0.000000;
} /* main */
083 arg_float : NG Except for this issue, I'm fine with this work for merging into master. |
Hi, @namhyung and @honggyukim. I really appreciate you both taking the time to review and give feedback each time, I'm learning a lot from you :)
Hmm... I wonder if it might be related to the |
I am investigating a previously presented issue that occurs when running the command let's summarize conclusions, which are twofold
the reason I did the second task was to see if other RISC-V environments had the same issue with the Previously, it didn't happen when using However, it turns out that this is not the case in the Each environment used for testing is shown below. [visionfive2 Board - Debian 12 ]
[RISC-V QEMU - Ubuntu 23.04 ]
[RISC-V QEMU - Ubuntu 22.04 ]
|
Can you please build tests/s-exp-float.c manually and check the output?
|
I manually compiled
|
Yeah, the return value seems not correct. But I don't think it should be a blocker at this point. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just wanted to fix it but I also think that it doesn't have block it from being merged into master. I will give LGTM now. Thanks very much for your effort and great contribution!
Good, can you please rebase your changes onto the current master? |
It's great to see the early work on RISC-V support finally coalescing into master, but I'm a little confused. That's because there are still issues with The @honggyukim Can we talk about this issue soon? @namhyung Yes, I will deal with it right away. |
This is a commit to ensure a successful build in a RISC-V 64bit environment, no functional behavior is implemented. Tested-by: Seonghee Jin <[email protected]> Co-authored-by: Honggyu Kim <[email protected]> Signed-off-by: Gichoel Choi <[email protected]>
In order to figure out the address of parent_loc, we need the frame pointer, but compiler optimization such as `-O2` in gcc removes the `fp` so we won't be able know where to change to hijack the return address to `mcount_return`. This problem only happens in gcc, but not in clang. To avoid the problem, `-fno-omit-frame-pointer` must be used when gcc optimization option is used in riscv64. Tested-by: Seonghee Jin <[email protected]> Tested-by: Paran Lee <[email protected]> Co-authored-by: Honggyu Kim <[email protected]> Signed-off-by: Gichoel Choi <[email protected]>
This is work to support argument handling on the RISC-V 64-bit architecture. If you are curious about how RISC-V 64bit register numbers map to DWARF register numbers, please refer to the 'RISC-V Run-time ABI Specification' in 'RISC-V ELF psABI'. Tested-by: Seonghee Jin <[email protected]> Tested-by: Jungmin Kim <[email protected]> Tested-by: SeokMin Kwon <[email protected]> Reviewed-by: Honggyu Kim <[email protected]> Signed-off-by: Gichoel Choi <[email protected]>
736369d
to
bacf545
Compare
It's because we don't want to hold this PR too long and so we can merge this early then handle floating point return value issue as a bug fix later. We're also aware that this work doesn't include plthook support so we know that this is incomplete somehow, but supporting all the features for a new architecture at once is difficult. We rather think that it'd be better to support RISC-V port incrementally. So I think it's good to consider this PR has completed the initial milestone for the RISC-V support. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The rebase is done so I can give LGTM again.
I now understand why it was merged, thank you. |
I've pushed check/riscv-fpret. Can you please take a look? |
I ran the
Wow... this surprisingly solved the I was curious as to how it was done, so I analyzed the commit and came up with the following conclusions.
However, I couldn't figure out why the problem occurred with the existing method of using the |
You used FYI, the return value is passed to
|
Thanks for the explanation. Your explanation above helped me understand why it is possible to avoid using the |
This pull request is a porting effort to enable successful, error-free builds on the RISC-V 64-bit architecture environment and to support tracing using the
mcount
function.This feature has also been tested on the
VisionFive2
RISC-V board.The following features are currently supported in the PR.
The following features are not yet supported
This PR was born out of this issue.
This work has been discussed previously with @honggyukim in the PR link below.
The Argument Handling feature was split into the PRs below and then merged back together.