1 /*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <trace/trace_marker.h>
17
18 #include <errno.h>
19 #include <fcntl.h>
20 #include <stdbool.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <sys/types.h>
25 #include <unistd.h>
26 #include "musl_log.h"
27
28 #ifndef MUSL_TEMP_FAILURE_RETRY
29 #define MUSL_TEMP_FAILURE_RETRY(exp) \
30 ({ \
31 long int _rc; \
32 do { \
33 _rc = (long int)(exp); \
34 } while ((_rc == -1) && (errno == EINTR)); \
35 _rc; \
36 })
37 #endif
38
39 // Check whether the user space trace function is enabled
is_enable_trace(void)40 static inline bool is_enable_trace(void)
41 {
42 return true;
43 }
44
45 // Get the fd of trace_marker
get_trace_marker_fd(void)46 static inline int get_trace_marker_fd(void)
47 {
48 int trace_marker_fd = MUSL_TEMP_FAILURE_RETRY(open("/sys/kernel/tracing/trace_marker", O_CLOEXEC | O_WRONLY | O_APPEND));
49 if (trace_marker_fd == -1) {
50 trace_marker_fd = MUSL_TEMP_FAILURE_RETRY(open("/sys/kernel/debug/tracing/trace_marker", O_CLOEXEC | O_WRONLY | O_APPEND));
51 }
52 return trace_marker_fd;
53 }
54
55 /* Write the function call information to the trace_marker node in kernel space,
56 used on the same thread as trace_marker_end(),with the symbol "B". */
trace_marker_begin(const char * message,const char * value)57 void trace_marker_begin(const char *message, const char *value)
58 {
59 if (!is_enable_trace() || message == NULL) {
60 return;
61 }
62
63 int trace_marker_fd = get_trace_marker_fd();
64 if (trace_marker_fd == -1) {
65 return;
66 }
67
68 char buf[TRACE_MARKER_MESSAGE_LEN] = {0};
69 int len = 0;
70 if (value == NULL) {
71 len = snprintf(buf, TRACE_MARKER_MESSAGE_LEN, "B|%d %s", getpid(), message);
72 } else {
73 len = snprintf(buf, TRACE_MARKER_MESSAGE_LEN, "B|%d|%s %s", getpid(), message, value);
74 }
75 if (len > 0 && len < sizeof(buf)) {
76 int ret = MUSL_TEMP_FAILURE_RETRY(write(trace_marker_fd, buf, len));
77 if (ret == -1) {
78 MUSL_LOGE("fail to write B. %d", ret);
79 }
80 } else {
81 MUSL_LOGE("B length error. %d", len);
82 }
83
84 // close file descriptor of trace_marker
85 close(trace_marker_fd);
86 }
87
88 /* Write the terminator to the trace_marker node of the kernel space,
89 used on the same thread as trace_marker_begin(),with the symbol "E". */
trace_marker_end(void)90 void trace_marker_end(void)
91 {
92 if (!is_enable_trace()) {
93 return;
94 }
95
96 int trace_marker_fd = get_trace_marker_fd();
97 if (trace_marker_fd == -1) {
98 return;
99 }
100
101 char buf[TRACE_MARKER_MESSAGE_LEN] = {0};
102 int len = snprintf(buf, TRACE_MARKER_MESSAGE_LEN, "E|%d", getpid());
103 if (len > 0 && len < sizeof(buf)) {
104 int ret = MUSL_TEMP_FAILURE_RETRY(write(trace_marker_fd, buf, len));
105 if (ret == -1) {
106 MUSL_LOGE("fail to write E. %d", ret);
107 }
108 } else {
109 MUSL_LOGE("E length error. %d", len);
110 }
111
112 // close file descriptor of trace_marker
113 close(trace_marker_fd);
114 }
115
116 /* Write the function call information to the trace_marker node in kernel space,
117 used in a different thread than trace_marker_async_end(),with the symbol "S". */
trace_marker_async_begin(const char * message,const char * value,int taskId)118 void trace_marker_async_begin(const char *message, const char *value, int taskId)
119 {
120 if (!is_enable_trace() || message == NULL) {
121 return;
122 }
123
124 int trace_marker_fd = get_trace_marker_fd();
125 if (trace_marker_fd == -1) {
126 return;
127 }
128
129 char buf[TRACE_MARKER_MESSAGE_LEN] = {0};
130 int len = 0;
131 if (value == NULL) {
132 len = snprintf(buf, TRACE_MARKER_MESSAGE_LEN, "S|%d|%s %d", getpid(), message, taskId);
133 } else {
134 len = snprintf(buf, TRACE_MARKER_MESSAGE_LEN, "S|%d|%s|%s %d", getpid(), message, value, taskId);
135 }
136 if (len > 0 && len < sizeof(buf)) {
137 int ret = MUSL_TEMP_FAILURE_RETRY(write(trace_marker_fd, buf, len));
138 if (ret == -1) {
139 MUSL_LOGE("fail to write S. %d", ret);
140 }
141 } else {
142 MUSL_LOGE("S length error. %d", len);
143 }
144
145 // close file descriptor of trace_marker
146 close(trace_marker_fd);
147 }
148
149 /* Write the terminator to the trace_marker node in kernel space,
150 used in a different thread than trace_marker_async_begin(),with the symbol "F". */
trace_marker_async_end(const char * message,const char * value,int taskId)151 void trace_marker_async_end(const char *message, const char *value, int taskId)
152 {
153 if (!is_enable_trace() || message == NULL) {
154 return;
155 }
156
157 int trace_marker_fd = get_trace_marker_fd();
158 if (trace_marker_fd == -1) {
159 return;
160 }
161
162 char buf[TRACE_MARKER_MESSAGE_LEN] = {0};
163 int len = 0;
164 if (value == NULL) {
165 len = snprintf(buf, TRACE_MARKER_MESSAGE_LEN, "F|%d|%s %d", getpid(), message, taskId);
166 } else {
167 len = snprintf(buf, TRACE_MARKER_MESSAGE_LEN, "F|%d|%s|%s %d", getpid(), message, value, taskId);
168 }
169 if (len > 0 && len < sizeof(buf)) {
170 int ret = MUSL_TEMP_FAILURE_RETRY(write(trace_marker_fd, buf, len));
171 if (ret == -1) {
172 MUSL_LOGE("fail to write F. %d", ret);
173 }
174 } else {
175 MUSL_LOGE("F length error. %d", len);
176 }
177
178 // close file descriptor of trace_marker
179 close(trace_marker_fd);
180 }
181
182 // A numeric variable used to mark a pre trace, with the symbol "C".
trace_marker_count(const char * message,int value)183 void trace_marker_count(const char *message, int value)
184 {
185 if (!is_enable_trace() || message == NULL) {
186 return;
187 }
188
189 int trace_marker_fd = get_trace_marker_fd();
190 if (trace_marker_fd == -1) {
191 return;
192 }
193
194 char buf[TRACE_MARKER_MESSAGE_LEN] = {0};
195 int len = snprintf(buf, TRACE_MARKER_MESSAGE_LEN, "C|%d|%s %d", getpid(), message, value);
196 if (len > 0 && len < sizeof(buf)) {
197 int ret = MUSL_TEMP_FAILURE_RETRY(write(trace_marker_fd, buf, len));
198 if (ret == -1) {
199 MUSL_LOGE("fail to write C. %d", ret);
200 }
201 } else {
202 MUSL_LOGE("C length error. %d", len);
203 }
204
205 // close file descriptor of trace_marker
206 close(trace_marker_fd);
207 }
208