write_profile_data.cpp 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. #include <dlfcn.h>
  2. #include <linux/limits.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <unistd.h>
  6. extern "C" {
  7. void __llvm_profile_initialize_file(void);
  8. int __llvm_profile_write_file(void);
  9. void __llvm_profile_set_filename(const char* filename_pattern);
  10. // there might no llmv rt, for example for the targets from contrib
  11. __attribute__((weak)) int __llvm_profile_write_file(void) {
  12. return 0;
  13. }
  14. __attribute__((weak)) void __llvm_profile_initialize_file(void) {
  15. }
  16. __attribute__((weak)) void __llvm_profile_set_filename(const char*) {
  17. }
  18. }
  19. namespace {
  20. void dummy() {
  21. }
  22. }
  23. bool getSoName(char* buff, size_t size) {
  24. // returns so name for shared objects and exe_name for binaries
  25. Dl_info dl_info = {0, 0, 0, 0};
  26. if (dladdr((void*)(intptr_t)dummy, &dl_info) != 0) {
  27. if (dl_info.dli_fname) {
  28. const char* name = dl_info.dli_fname;
  29. char real_path[PATH_MAX];
  30. const char* resolved = realpath(name, real_path);
  31. if (resolved != NULL)
  32. name = real_path;
  33. const char* lastSlash = strrchr(name, '/');
  34. if (!!lastSlash) {
  35. name = lastSlash + 1;
  36. }
  37. strncpy(buff, name, size);
  38. return true;
  39. }
  40. }
  41. return false;
  42. }
  43. bool getExeName(char* buff, size_t size) {
  44. ssize_t len = readlink("/proc/self/exe", buff, size);
  45. if (len <= 0) {
  46. return false;
  47. }
  48. buff[len] = '\0';
  49. char* lastSlash = strrchr(buff, '/');
  50. if (!!lastSlash) {
  51. strncpy(buff, lastSlash + 1, size);
  52. buff[(buff + len) - lastSlash] = '\0';
  53. }
  54. return true;
  55. }
  56. bool getSelfName(char* buff, size_t size) {
  57. #if defined(_musl_)
  58. return getExeName(buff, size);
  59. #else
  60. return getSoName(buff, size);
  61. #endif
  62. }
  63. void replaceFirst(char* data, size_t dsize, const char* pat, size_t psize, const char* repl, size_t rsize) {
  64. char* patPtr = strstr(data, pat);
  65. if (!patPtr) {
  66. return;
  67. }
  68. char tmp[PATH_MAX] = {0};
  69. char* tmpPtr = &tmp[0];
  70. strcpy(tmpPtr, patPtr + psize);
  71. strcpy(patPtr, repl);
  72. strcpy(patPtr + rsize, tmpPtr);
  73. data[dsize - psize + rsize] = '\0';
  74. }
  75. // Adds support of the specifier '%e' (executable filename (without path prefix)) to the LLVM_PROFILE_FILE
  76. void parseAndSetFilename() {
  77. const char* profile_file = getenv("LLVM_PROFILE_FILE");
  78. if (!profile_file)
  79. return;
  80. // __llvm_profile_set_filename doesn't copy name, so it must remain valid
  81. static char pattern[PATH_MAX] = {0};
  82. char* patternPtr = &pattern[0];
  83. strncpy(patternPtr, profile_file, PATH_MAX - 1);
  84. if (!!strstr(patternPtr, "%e")) {
  85. char buff[PATH_MAX] = {0};
  86. char* buffPtr = &buff[0];
  87. if (getSelfName(buffPtr, PATH_MAX)) {
  88. size_t patternSize = strlen(patternPtr);
  89. size_t buffSize = strlen(buffPtr);
  90. if (patternSize + buffSize >= PATH_MAX) {
  91. abort();
  92. }
  93. replaceFirst(patternPtr, patternSize, "%e", 2, buffPtr, buffSize);
  94. }
  95. }
  96. __llvm_profile_set_filename(patternPtr);
  97. }
  98. void __attribute__((constructor)) premain() {
  99. parseAndSetFilename();
  100. if (getenv("YA_COVERAGE_DUMP_PROFILE_AND_EXIT")) {
  101. __llvm_profile_initialize_file();
  102. int rc = __llvm_profile_write_file();
  103. if (!rc && getenv("YA_COVERAGE_DUMP_PROFILE_EXIT_CODE"))
  104. rc = atoi(getenv("YA_COVERAGE_DUMP_PROFILE_EXIT_CODE"));
  105. exit(rc);
  106. }
  107. }