location.cc 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. // Copyright (c) 2012 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "base/location.h"
  5. #include "base/compiler_specific.h"
  6. #include "base/strings/string_number_conversions.h"
  7. #include "base/strings/stringprintf.h"
  8. #include "base/trace_event/base_tracing.h"
  9. #include "build/build_config.h"
  10. #if defined(COMPILER_MSVC)
  11. #include <intrin.h>
  12. #endif
  13. namespace base {
  14. namespace {
  15. // Returns the length of the given null terminated c-string.
  16. constexpr size_t StrLen(const char* str) {
  17. size_t str_len = 0;
  18. for (str_len = 0; str[str_len] != '\0'; ++str_len)
  19. ;
  20. return str_len;
  21. }
  22. // Finds the length of the build folder prefix from the file path.
  23. // TODO(ssid): Strip prefixes from stored strings in the binary. This code only
  24. // skips the prefix while reading the file name strings at runtime.
  25. constexpr size_t StrippedFilePathPrefixLength() {
  26. constexpr char path[] = __FILE__;
  27. // Only keep the file path starting from the src directory.
  28. #if defined(__clang__) && defined(_MSC_VER)
  29. constexpr char stripped[] = "base\\location.cc";
  30. #else
  31. constexpr char stripped[] = "base/location.cc";
  32. #endif
  33. constexpr size_t path_len = StrLen(path);
  34. constexpr size_t stripped_len = StrLen(stripped);
  35. static_assert(path_len >= stripped_len,
  36. "Invalid file path for base/location.cc.");
  37. return path_len - stripped_len;
  38. }
  39. constexpr size_t kStrippedPrefixLength = StrippedFilePathPrefixLength();
  40. // Returns true if the |name| string has |prefix_len| characters in the prefix
  41. // and the suffix matches the |expected| string.
  42. // TODO(ssid): With C++20 we can make base::EndsWith() constexpr and use it
  43. // instead.
  44. constexpr bool StrEndsWith(const char* name,
  45. size_t prefix_len,
  46. const char* expected) {
  47. const size_t name_len = StrLen(name);
  48. const size_t expected_len = StrLen(expected);
  49. if (name_len != prefix_len + expected_len)
  50. return false;
  51. for (size_t i = 0; i < expected_len; ++i) {
  52. if (name[i + prefix_len] != expected[i])
  53. return false;
  54. }
  55. return true;
  56. }
  57. #if defined(__clang__) && defined(_MSC_VER)
  58. static_assert(StrEndsWith(__FILE__, kStrippedPrefixLength, "base\\location.cc"),
  59. "The file name does not match the expected prefix format.");
  60. #else
  61. static_assert(StrEndsWith(__FILE__, kStrippedPrefixLength, "base/location.cc"),
  62. "The file name does not match the expected prefix format.");
  63. #endif
  64. } // namespace
  65. Location::Location() = default;
  66. Location::Location(const Location& other) = default;
  67. Location::Location(Location&& other) noexcept = default;
  68. Location& Location::operator=(const Location& other) = default;
  69. Location::Location(const char* file_name, const void* program_counter)
  70. : file_name_(file_name), program_counter_(program_counter) {}
  71. Location::Location(const char* function_name,
  72. const char* file_name,
  73. int line_number,
  74. const void* program_counter)
  75. : function_name_(function_name),
  76. file_name_(file_name),
  77. line_number_(line_number),
  78. program_counter_(program_counter) {
  79. #if !BUILDFLAG(IS_NACL)
  80. // The program counter should not be null except in a default constructed
  81. // (empty) Location object. This value is used for identity, so if it doesn't
  82. // uniquely identify a location, things will break.
  83. //
  84. // The program counter isn't supported in NaCl so location objects won't work
  85. // properly in that context.
  86. DCHECK(program_counter);
  87. #endif
  88. }
  89. std::string Location::ToString() const {
  90. if (has_source_info()) {
  91. return std::string(function_name_) + "@" + file_name_ + ":" +
  92. NumberToString(line_number_);
  93. }
  94. return StringPrintf("pc:%p", program_counter_);
  95. }
  96. void Location::WriteIntoTrace(perfetto::TracedValue context) const {
  97. auto dict = std::move(context).WriteDictionary();
  98. dict.Add("function_name", function_name_);
  99. dict.Add("file_name", file_name_);
  100. dict.Add("line_number", line_number_);
  101. }
  102. #if defined(COMPILER_MSVC)
  103. #define RETURN_ADDRESS() _ReturnAddress()
  104. #elif defined(COMPILER_GCC) && !BUILDFLAG(IS_NACL)
  105. #define RETURN_ADDRESS() \
  106. __builtin_extract_return_addr(__builtin_return_address(0))
  107. #else
  108. #define RETURN_ADDRESS() nullptr
  109. #endif
  110. #if !BUILDFLAG(FROM_HERE_USES_LOCATION_BUILTINS)
  111. #if !BUILDFLAG(ENABLE_LOCATION_SOURCE)
  112. // static
  113. NOINLINE Location Location::CreateFromHere(const char* file_name) {
  114. return Location(file_name + kStrippedPrefixLength, RETURN_ADDRESS());
  115. }
  116. #else
  117. // static
  118. NOINLINE Location Location::CreateFromHere(const char* function_name,
  119. const char* file_name,
  120. int line_number) {
  121. return Location(function_name, file_name + kStrippedPrefixLength, line_number,
  122. RETURN_ADDRESS());
  123. }
  124. #endif
  125. #endif
  126. #if SUPPORTS_LOCATION_BUILTINS && BUILDFLAG(ENABLE_LOCATION_SOURCE)
  127. // static
  128. NOINLINE Location Location::Current(const char* function_name,
  129. const char* file_name,
  130. int line_number) {
  131. return Location(function_name, file_name + kStrippedPrefixLength, line_number,
  132. RETURN_ADDRESS());
  133. }
  134. #elif SUPPORTS_LOCATION_BUILTINS
  135. // static
  136. NOINLINE Location Location::Current(const char* file_name) {
  137. return Location(file_name + kStrippedPrefixLength, RETURN_ADDRESS());
  138. }
  139. #else
  140. // static
  141. NOINLINE Location Location::Current() {
  142. return Location(nullptr, RETURN_ADDRESS());
  143. }
  144. #endif
  145. //------------------------------------------------------------------------------
  146. NOINLINE const void* GetProgramCounter() {
  147. return RETURN_ADDRESS();
  148. }
  149. } // namespace base