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