Linux Perf
llvm-utils.c
Go to the documentation of this file.
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2015, Wang Nan <wangnan0@huawei.com>
4  * Copyright (C) 2015, Huawei Inc.
5  */
6 
7 #include <errno.h>
8 #include <limits.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <linux/err.h>
12 #include "debug.h"
13 #include "llvm-utils.h"
14 #include "config.h"
15 #include "util.h"
16 #include <sys/wait.h>
17 #include <subcmd/exec-cmd.h>
18 
19 #define CLANG_BPF_CMD_DEFAULT_TEMPLATE \
20  "$CLANG_EXEC -D__KERNEL__ -D__NR_CPUS__=$NR_CPUS "\
21  "-DLINUX_VERSION_CODE=$LINUX_VERSION_CODE " \
22  "$CLANG_OPTIONS $KERNEL_INC_OPTIONS $PERF_BPF_INC_OPTIONS " \
23  "-Wno-unused-value -Wno-pointer-sign " \
24  "-working-directory $WORKING_DIR " \
25  "-c \"$CLANG_SOURCE\" -target bpf -O2 -o -"
26 
28  .clang_path = "clang",
29  .clang_bpf_cmd_template = CLANG_BPF_CMD_DEFAULT_TEMPLATE,
30  .clang_opt = NULL,
31  .kbuild_dir = NULL,
32  .kbuild_opts = NULL,
33  .user_set_param = false,
34 };
35 
36 int perf_llvm_config(const char *var, const char *value)
37 {
38  if (!strstarts(var, "llvm."))
39  return 0;
40  var += sizeof("llvm.") - 1;
41 
42  if (!strcmp(var, "clang-path"))
43  llvm_param.clang_path = strdup(value);
44  else if (!strcmp(var, "clang-bpf-cmd-template"))
45  llvm_param.clang_bpf_cmd_template = strdup(value);
46  else if (!strcmp(var, "clang-opt"))
47  llvm_param.clang_opt = strdup(value);
48  else if (!strcmp(var, "kbuild-dir"))
49  llvm_param.kbuild_dir = strdup(value);
50  else if (!strcmp(var, "kbuild-opts"))
51  llvm_param.kbuild_opts = strdup(value);
52  else if (!strcmp(var, "dump-obj"))
53  llvm_param.dump_obj = !!perf_config_bool(var, value);
54  else {
55  pr_debug("Invalid LLVM config option: %s\n", value);
56  return -1;
57  }
58  llvm_param.user_set_param = true;
59  return 0;
60 }
61 
62 static int
63 search_program(const char *def, const char *name,
64  char *output)
65 {
66  char *env, *path, *tmp = NULL;
67  char buf[PATH_MAX];
68  int ret;
69 
70  output[0] = '\0';
71  if (def && def[0] != '\0') {
72  if (def[0] == '/') {
73  if (access(def, F_OK) == 0) {
74  strlcpy(output, def, PATH_MAX);
75  return 0;
76  }
77  } else if (def[0] != '\0')
78  name = def;
79  }
80 
81  env = getenv("PATH");
82  if (!env)
83  return -1;
84  env = strdup(env);
85  if (!env)
86  return -1;
87 
88  ret = -ENOENT;
89  path = strtok_r(env, ":", &tmp);
90  while (path) {
91  scnprintf(buf, sizeof(buf), "%s/%s", path, name);
92  if (access(buf, F_OK) == 0) {
93  strlcpy(output, buf, PATH_MAX);
94  ret = 0;
95  break;
96  }
97  path = strtok_r(NULL, ":", &tmp);
98  }
99 
100  free(env);
101  return ret;
102 }
103 
104 #define READ_SIZE 4096
105 static int
106 read_from_pipe(const char *cmd, void **p_buf, size_t *p_read_sz)
107 {
108  int err = 0;
109  void *buf = NULL;
110  FILE *file = NULL;
111  size_t read_sz = 0, buf_sz = 0;
112  char serr[STRERR_BUFSIZE];
113 
114  file = popen(cmd, "r");
115  if (!file) {
116  pr_err("ERROR: unable to popen cmd: %s\n",
117  str_error_r(errno, serr, sizeof(serr)));
118  return -EINVAL;
119  }
120 
121  while (!feof(file) && !ferror(file)) {
122  /*
123  * Make buf_sz always have obe byte extra space so we
124  * can put '\0' there.
125  */
126  if (buf_sz - read_sz < READ_SIZE + 1) {
127  void *new_buf;
128 
129  buf_sz = read_sz + READ_SIZE + 1;
130  new_buf = realloc(buf, buf_sz);
131 
132  if (!new_buf) {
133  pr_err("ERROR: failed to realloc memory\n");
134  err = -ENOMEM;
135  goto errout;
136  }
137 
138  buf = new_buf;
139  }
140  read_sz += fread(buf + read_sz, 1, READ_SIZE, file);
141  }
142 
143  if (buf_sz - read_sz < 1) {
144  pr_err("ERROR: internal error\n");
145  err = -EINVAL;
146  goto errout;
147  }
148 
149  if (ferror(file)) {
150  pr_err("ERROR: error occurred when reading from pipe: %s\n",
151  str_error_r(errno, serr, sizeof(serr)));
152  err = -EIO;
153  goto errout;
154  }
155 
156  err = WEXITSTATUS(pclose(file));
157  file = NULL;
158  if (err) {
159  err = -EINVAL;
160  goto errout;
161  }
162 
163  /*
164  * If buf is string, give it terminal '\0' to make our life
165  * easier. If buf is not string, that '\0' is out of space
166  * indicated by read_sz so caller won't even notice it.
167  */
168  ((char *)buf)[read_sz] = '\0';
169 
170  if (!p_buf)
171  free(buf);
172  else
173  *p_buf = buf;
174 
175  if (p_read_sz)
176  *p_read_sz = read_sz;
177  return 0;
178 
179 errout:
180  if (file)
181  pclose(file);
182  free(buf);
183  if (p_buf)
184  *p_buf = NULL;
185  if (p_read_sz)
186  *p_read_sz = 0;
187  return err;
188 }
189 
190 static inline void
191 force_set_env(const char *var, const char *value)
192 {
193  if (value) {
194  setenv(var, value, 1);
195  pr_debug("set env: %s=%s\n", var, value);
196  } else {
197  unsetenv(var);
198  pr_debug("unset env: %s\n", var);
199  }
200 }
201 
202 static void
204 {
205  pr_err(
206 " \tLLVM 3.7 or newer is required. Which can be found from http://llvm.org\n"
207 " \tYou may want to try git trunk:\n"
208 " \t\tgit clone http://llvm.org/git/llvm.git\n"
209 " \t\t and\n"
210 " \t\tgit clone http://llvm.org/git/clang.git\n\n"
211 " \tOr fetch the latest clang/llvm 3.7 from pre-built llvm packages for\n"
212 " \tdebian/ubuntu:\n"
213 " \t\thttp://llvm.org/apt\n\n"
214 " \tIf you are using old version of clang, change 'clang-bpf-cmd-template'\n"
215 " \toption in [llvm] section of ~/.perfconfig to:\n\n"
216 " \t \"$CLANG_EXEC $CLANG_OPTIONS $KERNEL_INC_OPTIONS $PERF_BPF_INC_OPTIONS \\\n"
217 " \t -working-directory $WORKING_DIR -c $CLANG_SOURCE \\\n"
218 " \t -emit-llvm -o - | /path/to/llc -march=bpf -filetype=obj -o -\"\n"
219 " \t(Replace /path/to/llc with path to your llc)\n\n"
220 );
221 }
222 
223 static int detect_kbuild_dir(char **kbuild_dir)
224 {
225  const char *test_dir = llvm_param.kbuild_dir;
226  const char *prefix_dir = "";
227  const char *suffix_dir = "";
228 
229  char *autoconf_path;
230 
231  int err;
232 
233  if (!test_dir) {
234  /* _UTSNAME_LENGTH is 65 */
235  char release[128];
236 
237  err = fetch_kernel_version(NULL, release,
238  sizeof(release));
239  if (err)
240  return -EINVAL;
241 
242  test_dir = release;
243  prefix_dir = "/lib/modules/";
244  suffix_dir = "/build";
245  }
246 
247  err = asprintf(&autoconf_path, "%s%s%s/include/generated/autoconf.h",
248  prefix_dir, test_dir, suffix_dir);
249  if (err < 0)
250  return -ENOMEM;
251 
252  if (access(autoconf_path, R_OK) == 0) {
253  free(autoconf_path);
254 
255  err = asprintf(kbuild_dir, "%s%s%s", prefix_dir, test_dir,
256  suffix_dir);
257  if (err < 0)
258  return -ENOMEM;
259  return 0;
260  }
261  free(autoconf_path);
262  return -ENOENT;
263 }
264 
265 static const char *kinc_fetch_script =
266 "#!/usr/bin/env sh\n"
267 "if ! test -d \"$KBUILD_DIR\"\n"
268 "then\n"
269 " exit -1\n"
270 "fi\n"
271 "if ! test -f \"$KBUILD_DIR/include/generated/autoconf.h\"\n"
272 "then\n"
273 " exit -1\n"
274 "fi\n"
275 "TMPDIR=`mktemp -d`\n"
276 "if test -z \"$TMPDIR\"\n"
277 "then\n"
278 " exit -1\n"
279 "fi\n"
280 "cat << EOF > $TMPDIR/Makefile\n"
281 "obj-y := dummy.o\n"
282 "\\$(obj)/%.o: \\$(src)/%.c\n"
283 "\t@echo -n \"\\$(NOSTDINC_FLAGS) \\$(LINUXINCLUDE) \\$(EXTRA_CFLAGS)\"\n"
284 "EOF\n"
285 "touch $TMPDIR/dummy.c\n"
286 "make -s -C $KBUILD_DIR M=$TMPDIR $KBUILD_OPTS dummy.o 2>/dev/null\n"
287 "RET=$?\n"
288 "rm -rf $TMPDIR\n"
289 "exit $RET\n";
290 
291 void llvm__get_kbuild_opts(char **kbuild_dir, char **kbuild_include_opts)
292 {
293  static char *saved_kbuild_dir;
294  static char *saved_kbuild_include_opts;
295  int err;
296 
297  if (!kbuild_dir || !kbuild_include_opts)
298  return;
299 
300  *kbuild_dir = NULL;
301  *kbuild_include_opts = NULL;
302 
303  if (saved_kbuild_dir && saved_kbuild_include_opts &&
304  !IS_ERR(saved_kbuild_dir) && !IS_ERR(saved_kbuild_include_opts)) {
305  *kbuild_dir = strdup(saved_kbuild_dir);
306  *kbuild_include_opts = strdup(saved_kbuild_include_opts);
307 
308  if (*kbuild_dir && *kbuild_include_opts)
309  return;
310 
311  zfree(kbuild_dir);
312  zfree(kbuild_include_opts);
313  /*
314  * Don't fall through: it may breaks saved_kbuild_dir and
315  * saved_kbuild_include_opts if detect them again when
316  * memory is low.
317  */
318  return;
319  }
320 
321  if (llvm_param.kbuild_dir && !llvm_param.kbuild_dir[0]) {
322  pr_debug("[llvm.kbuild-dir] is set to \"\" deliberately.\n");
323  pr_debug("Skip kbuild options detection.\n");
324  goto errout;
325  }
326 
327  err = detect_kbuild_dir(kbuild_dir);
328  if (err) {
329  pr_warning(
330 "WARNING:\tunable to get correct kernel building directory.\n"
331 "Hint:\tSet correct kbuild directory using 'kbuild-dir' option in [llvm]\n"
332 " \tsection of ~/.perfconfig or set it to \"\" to suppress kbuild\n"
333 " \tdetection.\n\n");
334  goto errout;
335  }
336 
337  pr_debug("Kernel build dir is set to %s\n", *kbuild_dir);
338  force_set_env("KBUILD_DIR", *kbuild_dir);
339  force_set_env("KBUILD_OPTS", llvm_param.kbuild_opts);
341  (void **)kbuild_include_opts,
342  NULL);
343  if (err) {
344  pr_warning(
345 "WARNING:\tunable to get kernel include directories from '%s'\n"
346 "Hint:\tTry set clang include options using 'clang-bpf-cmd-template'\n"
347 " \toption in [llvm] section of ~/.perfconfig and set 'kbuild-dir'\n"
348 " \toption in [llvm] to \"\" to suppress this detection.\n\n",
349  *kbuild_dir);
350 
351  free(*kbuild_dir);
352  *kbuild_dir = NULL;
353  goto errout;
354  }
355 
356  pr_debug("include option is set to %s\n", *kbuild_include_opts);
357 
358  saved_kbuild_dir = strdup(*kbuild_dir);
359  saved_kbuild_include_opts = strdup(*kbuild_include_opts);
360 
361  if (!saved_kbuild_dir || !saved_kbuild_include_opts) {
362  zfree(&saved_kbuild_dir);
363  zfree(&saved_kbuild_include_opts);
364  }
365  return;
366 errout:
367  saved_kbuild_dir = ERR_PTR(-EINVAL);
368  saved_kbuild_include_opts = ERR_PTR(-EINVAL);
369 }
370 
372 {
373  static int nr_cpus_avail = 0;
374  char serr[STRERR_BUFSIZE];
375 
376  if (nr_cpus_avail > 0)
377  return nr_cpus_avail;
378 
379  nr_cpus_avail = sysconf(_SC_NPROCESSORS_CONF);
380  if (nr_cpus_avail <= 0) {
381  pr_err(
382 "WARNING:\tunable to get available CPUs in this system: %s\n"
383 " \tUse 128 instead.\n", str_error_r(errno, serr, sizeof(serr)));
384  nr_cpus_avail = 128;
385  }
386  return nr_cpus_avail;
387 }
388 
389 void llvm__dump_obj(const char *path, void *obj_buf, size_t size)
390 {
391  char *obj_path = strdup(path);
392  FILE *fp;
393  char *p;
394 
395  if (!obj_path) {
396  pr_warning("WARNING: Not enough memory, skip object dumping\n");
397  return;
398  }
399 
400  p = strrchr(obj_path, '.');
401  if (!p || (strcmp(p, ".c") != 0)) {
402  pr_warning("WARNING: invalid llvm source path: '%s', skip object dumping\n",
403  obj_path);
404  goto out;
405  }
406 
407  p[1] = 'o';
408  fp = fopen(obj_path, "wb");
409  if (!fp) {
410  pr_warning("WARNING: failed to open '%s': %s, skip object dumping\n",
411  obj_path, strerror(errno));
412  goto out;
413  }
414 
415  pr_info("LLVM: dumping %s\n", obj_path);
416  if (fwrite(obj_buf, size, 1, fp) != 1)
417  pr_warning("WARNING: failed to write to file '%s': %s, skip object dumping\n",
418  obj_path, strerror(errno));
419  fclose(fp);
420 out:
421  free(obj_path);
422 }
423 
424 int llvm__compile_bpf(const char *path, void **p_obj_buf,
425  size_t *p_obj_buf_sz)
426 {
427  size_t obj_buf_sz;
428  void *obj_buf = NULL;
429  int err, nr_cpus_avail;
430  unsigned int kernel_version;
431  char linux_version_code_str[64];
432  const char *clang_opt = llvm_param.clang_opt;
433  char clang_path[PATH_MAX], abspath[PATH_MAX], nr_cpus_avail_str[64];
434  char serr[STRERR_BUFSIZE];
435  char *kbuild_dir = NULL, *kbuild_include_opts = NULL,
436  *perf_bpf_include_opts = NULL;
437  const char *template = llvm_param.clang_bpf_cmd_template;
438  char *command_echo = NULL, *command_out;
439  char *perf_include_dir = system_path(PERF_INCLUDE_DIR);
440 
441  if (path[0] != '-' && realpath(path, abspath) == NULL) {
442  err = errno;
443  pr_err("ERROR: problems with path %s: %s\n",
444  path, str_error_r(err, serr, sizeof(serr)));
445  return -err;
446  }
447 
448  if (!template)
450 
451  err = search_program(llvm_param.clang_path,
452  "clang", clang_path);
453  if (err) {
454  pr_err(
455 "ERROR:\tunable to find clang.\n"
456 "Hint:\tTry to install latest clang/llvm to support BPF. Check your $PATH\n"
457 " \tand 'clang-path' option in [llvm] section of ~/.perfconfig.\n");
458  version_notice();
459  return -ENOENT;
460  }
461 
462  /*
463  * This is an optional work. Even it fail we can continue our
464  * work. Needn't to check error return.
465  */
466  llvm__get_kbuild_opts(&kbuild_dir, &kbuild_include_opts);
467 
468  nr_cpus_avail = llvm__get_nr_cpus();
469  snprintf(nr_cpus_avail_str, sizeof(nr_cpus_avail_str), "%d",
470  nr_cpus_avail);
471 
472  if (fetch_kernel_version(&kernel_version, NULL, 0))
473  kernel_version = 0;
474 
475  snprintf(linux_version_code_str, sizeof(linux_version_code_str),
476  "0x%x", kernel_version);
477  if (asprintf(&perf_bpf_include_opts, "-I%s/bpf", perf_include_dir) < 0)
478  goto errout;
479  force_set_env("NR_CPUS", nr_cpus_avail_str);
480  force_set_env("LINUX_VERSION_CODE", linux_version_code_str);
481  force_set_env("CLANG_EXEC", clang_path);
482  force_set_env("CLANG_OPTIONS", clang_opt);
483  force_set_env("KERNEL_INC_OPTIONS", kbuild_include_opts);
484  force_set_env("PERF_BPF_INC_OPTIONS", perf_bpf_include_opts);
485  force_set_env("WORKING_DIR", kbuild_dir ? : ".");
486 
487  /*
488  * Since we may reset clang's working dir, path of source file
489  * should be transferred into absolute path, except we want
490  * stdin to be source file (testing).
491  */
492  force_set_env("CLANG_SOURCE",
493  (path[0] == '-') ? path : abspath);
494 
495  pr_debug("llvm compiling command template: %s\n", template);
496 
497  if (asprintf(&command_echo, "echo -n \"%s\"", template) < 0)
498  goto errout;
499 
500  err = read_from_pipe(command_echo, (void **) &command_out, NULL);
501  if (err)
502  goto errout;
503 
504  pr_debug("llvm compiling command : %s\n", command_out);
505 
506  err = read_from_pipe(template, &obj_buf, &obj_buf_sz);
507  if (err) {
508  pr_err("ERROR:\tunable to compile %s\n", path);
509  pr_err("Hint:\tCheck error message shown above.\n");
510  pr_err("Hint:\tYou can also pre-compile it into .o using:\n");
511  pr_err(" \t\tclang -target bpf -O2 -c %s\n", path);
512  pr_err(" \twith proper -I and -D options.\n");
513  goto errout;
514  }
515 
516  free(command_echo);
517  free(command_out);
518  free(kbuild_dir);
519  free(kbuild_include_opts);
520  free(perf_bpf_include_opts);
521  free(perf_include_dir);
522 
523  if (!p_obj_buf)
524  free(obj_buf);
525  else
526  *p_obj_buf = obj_buf;
527 
528  if (p_obj_buf_sz)
529  *p_obj_buf_sz = obj_buf_sz;
530  return 0;
531 errout:
532  free(command_echo);
533  free(kbuild_dir);
534  free(kbuild_include_opts);
535  free(obj_buf);
536  free(perf_bpf_include_opts);
537  free(perf_include_dir);
538  if (p_obj_buf)
539  *p_obj_buf = NULL;
540  if (p_obj_buf_sz)
541  *p_obj_buf_sz = 0;
542  return err;
543 }
544 
546 {
547  char clang_path[PATH_MAX];
548 
549  return search_program(llvm_param.clang_path, "clang", clang_path);
550 }
bool dump_obj
Definition: llvm-utils.h:37
int fetch_kernel_version(unsigned int *puint, char *str, size_t str_size)
Definition: util.c:447
int value
Definition: python.c:1143
const char * clang_bpf_cmd_template
Definition: llvm-utils.h:23
static void version_notice(void)
Definition: llvm-utils.c:203
size_t size
Definition: evsel.c:60
def strerror(nr)
Definition: Util.py:86
int int err
Definition: 5sec.c:44
int perf_config_bool(const char *name, const char *value)
Definition: config.c:389
const char * kbuild_dir
Definition: llvm-utils.h:27
#define CLANG_BPF_CMD_DEFAULT_TEMPLATE
Definition: llvm-utils.c:19
int perf_llvm_config(const char *var, const char *value)
Definition: llvm-utils.c:36
#define pr_err(fmt,...)
Definition: json.h:21
static void force_set_env(const char *var, const char *value)
Definition: llvm-utils.c:191
#define READ_SIZE
Definition: llvm-utils.c:104
static int search_program(const char *def, const char *name, char *output)
Definition: llvm-utils.c:63
const char * name
#define pr_debug(fmt,...)
Definition: json.h:27
static int detect_kbuild_dir(char **kbuild_dir)
Definition: llvm-utils.c:223
bool user_set_param
Definition: llvm-utils.h:44
const char * clang_opt
Definition: llvm-utils.h:25
static const char * kinc_fetch_script
Definition: llvm-utils.c:265
#define PATH_MAX
Definition: jevents.c:1042
void llvm__get_kbuild_opts(char **kbuild_dir, char **kbuild_include_opts)
Definition: llvm-utils.c:291
int llvm__get_nr_cpus(void)
Definition: llvm-utils.c:371
#define zfree(ptr)
Definition: util.h:25
static int read_from_pipe(const char *cmd, void **p_buf, size_t *p_read_sz)
Definition: llvm-utils.c:106
static struct @9 output[OUTPUT_TYPE_MAX]
int llvm__compile_bpf(const char *path, void **p_obj_buf, size_t *p_obj_buf_sz)
Definition: llvm-utils.c:424
int llvm__search_clang(void)
Definition: llvm-utils.c:545
#define pr_info(fmt,...)
Definition: json.h:24
#define STRERR_BUFSIZE
Definition: debug.h:43
void free(void *)
void llvm__dump_obj(const char *path, void *obj_buf, size_t size)
Definition: llvm-utils.c:389
const char * clang_path
Definition: llvm-utils.h:13
#define pr_warning(fmt,...)
Definition: debug.h:25
const char * kbuild_opts
Definition: llvm-utils.h:32