2 * Copyright (C) 2020 EfficiOS, Inc.
4 * SPDX-License-Identifier: GPL-2.0-only
10 #include <sys/types.h>
14 #include "common/compat/getenv.h"
15 #include "common/string-utils/string-utils.h"
16 #include "common/utils.h"
17 #include "lttng/constant.h"
22 * Walk the directories in the PATH environment variable to find the target
23 * binary passed as parameter.
25 * On success, the full path of the binary is copied in binary_full_path out
26 * parameter. This buffer is allocated by the caller and must be at least
27 * LTTNG_PATH_MAX bytes long.
28 * On failure, returns -1;
31 int walk_command_search_path(const char *binary
, char *binary_full_path
)
33 char *tentative_binary_path
= NULL
;
34 char *command_search_path
= NULL
;
35 char *curr_search_dir_end
= NULL
;
36 char *curr_search_dir
= NULL
;
37 struct stat stat_output
;
40 command_search_path
= lttng_secure_getenv("PATH");
41 if (!command_search_path
) {
47 * Duplicate the $PATH string as the char pointer returned by getenv() should
50 command_search_path
= strdup(command_search_path
);
51 if (!command_search_path
) {
57 * This char array is used to concatenate path to binary to look for
60 tentative_binary_path
= zmalloc(LTTNG_PATH_MAX
* sizeof(char));
61 if (!tentative_binary_path
) {
66 curr_search_dir
= command_search_path
;
69 * Split on ':'. The return value of this call points to the
72 curr_search_dir_end
= strchr(curr_search_dir
, ':');
73 if (curr_search_dir_end
!= NULL
) {
75 * Add a NULL byte to the end of the first token so it
76 * can be used as a string.
78 curr_search_dir_end
[0] = '\0';
81 /* Empty the tentative path */
82 memset(tentative_binary_path
, 0, LTTNG_PATH_MAX
* sizeof(char));
85 * Build the tentative path to the binary using the current
86 * search directory and the name of the binary.
88 ret
= snprintf(tentative_binary_path
, LTTNG_PATH_MAX
, "%s/%s",
89 curr_search_dir
, binary
);
91 goto free_binary_path
;
93 if (ret
< LTTNG_PATH_MAX
) {
95 * Use STAT(2) to see if the file exists.
97 ret
= stat(tentative_binary_path
, &stat_output
);
100 * Verify that it is a regular file or a
101 * symlink and not a special file (e.g.
104 if (S_ISREG(stat_output
.st_mode
)
105 || S_ISLNK(stat_output
.st_mode
)) {
107 * Found a match, set the out parameter
108 * and return success.
110 ret
= lttng_strncpy(binary_full_path
,
111 tentative_binary_path
,
114 ERR("Source path does not fit "
115 "in destination buffer.");
117 goto free_binary_path
;
121 /* Go to the next entry in the $PATH variable. */
122 curr_search_dir
= curr_search_dir_end
+ 1;
123 } while (curr_search_dir_end
!= NULL
);
126 free(tentative_binary_path
);
128 free(command_search_path
);
134 * Check if the symbol field passed by the user is in fact an address or an
135 * offset from a symbol. Those two instrumentation types are not supported yet.
136 * It's expected to be a common mistake because of the existing --probe option
137 * that does support these formats.
139 * Here are examples of these unsupported formats for the --userspace-probe
141 * elf:/path/to/binary:0x400430
142 * elf:/path/to/binary:4194364
143 * elf:/path/to/binary:my_symbol+0x323
144 * elf:/path/to/binary:my_symbol+43
147 int warn_userspace_probe_syntax(const char *symbol
)
151 /* Check if the symbol field is an hex address. */
152 ret
= sscanf(symbol
, "0x%*x");
154 /* If there is a match, print a warning and return an error. */
155 ERR("Userspace probe on address not supported yet.");
156 ret
= CMD_UNSUPPORTED
;
160 /* Check if the symbol field is an decimal address. */
161 ret
= sscanf(symbol
, "%*u");
163 /* If there is a match, print a warning and return an error. */
164 ERR("Userspace probe on address not supported yet.");
165 ret
= CMD_UNSUPPORTED
;
169 /* Check if the symbol field is symbol+hex_offset. */
170 ret
= sscanf(symbol
, "%*[^+]+0x%*x");
172 /* If there is a match, print a warning and return an error. */
173 ERR("Userspace probe on symbol+offset not supported yet.");
174 ret
= CMD_UNSUPPORTED
;
178 /* Check if the symbol field is symbol+decimal_offset. */
179 ret
= sscanf(symbol
, "%*[^+]+%*u");
181 /* If there is a match, print a warning and return an error. */
182 ERR("Userspace probe on symbol+offset not supported yet.");
183 ret
= CMD_UNSUPPORTED
;
194 * Parse userspace probe options
195 * Set the userspace probe fields in the lttng_event struct and set the
196 * target_path to the path to the binary.
199 int parse_userspace_probe_opts(const char *opt
,
200 struct lttng_userspace_probe_location
**probe_location
)
202 int ret
= CMD_SUCCESS
;
204 char **tokens
= NULL
;
205 char *target_path
= NULL
;
206 char *unescaped_target_path
= NULL
;
207 char *real_target_path
= NULL
;
208 char *symbol_name
= NULL
, *probe_name
= NULL
, *provider_name
= NULL
;
209 struct lttng_userspace_probe_location
*probe_location_local
= NULL
;
210 struct lttng_userspace_probe_location_lookup_method
*lookup_method
= NULL
;
215 * userspace probe fields are separated by ':'.
217 tokens
= strutils_split(opt
, ':', 1);
218 num_token
= strutils_array_of_strings_len(tokens
);
221 * Early sanity check that the number of parameter is between 2 and 4
224 * std:PATH:PROVIDER_NAME:PROBE_NAME
225 * PATH:SYMBOL (same behavior as ELF)
227 if (num_token
< 2 || num_token
> 4) {
233 * Looking up the first parameter will tell the technique to use to
234 * interpret the userspace probe/function description.
238 /* When the probe type is omitted we assume ELF for now. */
240 if (num_token
== 3 && strcmp(tokens
[0], "elf") == 0) {
241 target_path
= tokens
[1];
242 symbol_name
= tokens
[2];
243 } else if (num_token
== 2) {
244 target_path
= tokens
[0];
245 symbol_name
= tokens
[1];
251 lttng_userspace_probe_location_lookup_method_function_elf_create();
252 if (!lookup_method
) {
253 WARN("Failed to create ELF lookup method");
259 if (strcmp(tokens
[0], "sdt") == 0) {
260 target_path
= tokens
[1];
261 provider_name
= tokens
[2];
262 probe_name
= tokens
[3];
268 lttng_userspace_probe_location_lookup_method_tracepoint_sdt_create();
269 if (!lookup_method
) {
270 WARN("Failed to create SDT lookup method");
280 /* strutils_unescape_string allocates a new char *. */
281 unescaped_target_path
= strutils_unescape_string(target_path
, 0);
282 if (!unescaped_target_path
) {
288 * If there is not forward slash in the path. Walk the $PATH else
291 if (strchr(unescaped_target_path
, '/') == NULL
) {
292 /* Walk the $PATH variable to find the targeted binary. */
293 real_target_path
= zmalloc(LTTNG_PATH_MAX
* sizeof(char));
294 if (!real_target_path
) {
295 PERROR("Error allocating path buffer");
299 ret
= walk_command_search_path(unescaped_target_path
, real_target_path
);
301 ERR("Binary not found.");
307 * Expand references to `/./` and `/../`. This function does not check
308 * if the file exists. This call returns an allocated buffer on
311 real_target_path
= utils_expand_path_keep_symlink(unescaped_target_path
);
312 if (!real_target_path
) {
313 ERR("Error expanding the path to binary.");
319 * Check if the file exists using access(2), If it does not,
322 ret
= access(real_target_path
, F_OK
);
324 ERR("Cannot find binary at path: %s.", real_target_path
);
330 switch (lttng_userspace_probe_location_lookup_method_get_type(lookup_method
)) {
331 case LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_FUNCTION_ELF
:
333 * Check for common mistakes in userspace probe description syntax.
335 ret
= warn_userspace_probe_syntax(symbol_name
);
340 probe_location_local
= lttng_userspace_probe_location_function_create(
341 real_target_path
, symbol_name
, lookup_method
);
342 if (!probe_location_local
) {
343 WARN("Failed to create function probe location");
348 /* Ownership transferred to probe_location. */
349 lookup_method
= NULL
;
351 case LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_TRACEPOINT_SDT
:
352 probe_location_local
= lttng_userspace_probe_location_tracepoint_create(
353 real_target_path
, provider_name
, probe_name
, lookup_method
);
354 if (!probe_location_local
) {
355 WARN("Failed to create function probe location");
360 /* Ownership transferred to probe_location. */
361 lookup_method
= NULL
;
369 * Everything went fine, transfer ownership of probe location to
372 *probe_location
= probe_location_local
;
373 probe_location_local
= NULL
;
376 lttng_userspace_probe_location_destroy(probe_location_local
);
377 lttng_userspace_probe_location_lookup_method_destroy(lookup_method
);
378 strutils_free_null_terminated_array_of_strings(tokens
);
380 * Freeing both char * here makes the error handling simplier. free()
381 * performs not action if the pointer is NULL.
383 free(real_target_path
);
384 free(unescaped_target_path
);