1 //===-- ClangExpressionSourceCode.cpp ---------------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "ClangExpressionSourceCode.h" 10 11 #include "Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h" 12 #include "Plugins/ExpressionParser/Clang/ClangPersistentVariables.h" 13 #include "lldb/Symbol/Block.h" 14 #include "lldb/Symbol/CompileUnit.h" 15 #include "lldb/Symbol/DebugMacros.h" 16 #include "lldb/Symbol/TypeSystem.h" 17 #include "lldb/Symbol/VariableList.h" 18 #include "lldb/Target/ExecutionContext.h" 19 #include "lldb/Target/Language.h" 20 #include "lldb/Target/Platform.h" 21 #include "lldb/Target/StackFrame.h" 22 #include "lldb/Target/Target.h" 23 #include "lldb/Utility/StreamString.h" 24 25 using namespace lldb_private; 26 27 const char *ClangExpressionSourceCode::g_expression_prefix = R"( 28 #ifndef NULL 29 #define NULL (__null) 30 #endif 31 #ifndef Nil 32 #define Nil (__null) 33 #endif 34 #ifndef nil 35 #define nil (__null) 36 #endif 37 #ifndef YES 38 #define YES ((BOOL)1) 39 #endif 40 #ifndef NO 41 #define NO ((BOOL)0) 42 #endif 43 typedef __INT8_TYPE__ int8_t; 44 typedef __UINT8_TYPE__ uint8_t; 45 typedef __INT16_TYPE__ int16_t; 46 typedef __UINT16_TYPE__ uint16_t; 47 typedef __INT32_TYPE__ int32_t; 48 typedef __UINT32_TYPE__ uint32_t; 49 typedef __INT64_TYPE__ int64_t; 50 typedef __UINT64_TYPE__ uint64_t; 51 typedef __INTPTR_TYPE__ intptr_t; 52 typedef __UINTPTR_TYPE__ uintptr_t; 53 typedef __SIZE_TYPE__ size_t; 54 typedef __PTRDIFF_TYPE__ ptrdiff_t; 55 typedef unsigned short unichar; 56 extern "C" 57 { 58 int printf(const char * __restrict, ...); 59 } 60 )"; 61 62 static const char *c_start_marker = " /*LLDB_BODY_START*/\n "; 63 static const char *c_end_marker = ";\n /*LLDB_BODY_END*/\n"; 64 65 namespace { 66 67 class AddMacroState { 68 enum State { 69 CURRENT_FILE_NOT_YET_PUSHED, 70 CURRENT_FILE_PUSHED, 71 CURRENT_FILE_POPPED 72 }; 73 74 public: 75 AddMacroState(const FileSpec ¤t_file, const uint32_t current_file_line) 76 : m_state(CURRENT_FILE_NOT_YET_PUSHED), m_current_file(current_file), 77 m_current_file_line(current_file_line) {} 78 79 void StartFile(const FileSpec &file) { 80 m_file_stack.push_back(file); 81 if (file == m_current_file) 82 m_state = CURRENT_FILE_PUSHED; 83 } 84 85 void EndFile() { 86 if (m_file_stack.size() == 0) 87 return; 88 89 FileSpec old_top = m_file_stack.back(); 90 m_file_stack.pop_back(); 91 if (old_top == m_current_file) 92 m_state = CURRENT_FILE_POPPED; 93 } 94 95 // An entry is valid if it occurs before the current line in the current 96 // file. 97 bool IsValidEntry(uint32_t line) { 98 switch (m_state) { 99 case CURRENT_FILE_NOT_YET_PUSHED: 100 return true; 101 case CURRENT_FILE_PUSHED: 102 // If we are in file included in the current file, the entry should be 103 // added. 104 if (m_file_stack.back() != m_current_file) 105 return true; 106 107 return line < m_current_file_line; 108 default: 109 return false; 110 } 111 } 112 113 private: 114 std::vector<FileSpec> m_file_stack; 115 State m_state; 116 FileSpec m_current_file; 117 uint32_t m_current_file_line; 118 }; 119 120 } // anonymous namespace 121 122 static void AddMacros(const DebugMacros *dm, CompileUnit *comp_unit, 123 AddMacroState &state, StreamString &stream) { 124 if (dm == nullptr) 125 return; 126 127 for (size_t i = 0; i < dm->GetNumMacroEntries(); i++) { 128 const DebugMacroEntry &entry = dm->GetMacroEntryAtIndex(i); 129 uint32_t line; 130 131 switch (entry.GetType()) { 132 case DebugMacroEntry::DEFINE: 133 if (state.IsValidEntry(entry.GetLineNumber())) 134 stream.Printf("#define %s\n", entry.GetMacroString().AsCString()); 135 else 136 return; 137 break; 138 case DebugMacroEntry::UNDEF: 139 if (state.IsValidEntry(entry.GetLineNumber())) 140 stream.Printf("#undef %s\n", entry.GetMacroString().AsCString()); 141 else 142 return; 143 break; 144 case DebugMacroEntry::START_FILE: 145 line = entry.GetLineNumber(); 146 if (state.IsValidEntry(line)) 147 state.StartFile(entry.GetFileSpec(comp_unit)); 148 else 149 return; 150 break; 151 case DebugMacroEntry::END_FILE: 152 state.EndFile(); 153 break; 154 case DebugMacroEntry::INDIRECT: 155 AddMacros(entry.GetIndirectDebugMacros(), comp_unit, state, stream); 156 break; 157 default: 158 // This is an unknown/invalid entry. Ignore. 159 break; 160 } 161 } 162 } 163 164 static void AddLocalVariableDecls(const lldb::VariableListSP &var_list_sp, 165 StreamString &stream) { 166 for (size_t i = 0; i < var_list_sp->GetSize(); i++) { 167 lldb::VariableSP var_sp = var_list_sp->GetVariableAtIndex(i); 168 169 ConstString var_name = var_sp->GetName(); 170 if (!var_name || var_name == ConstString("this") || 171 var_name == ConstString(".block_descriptor")) 172 continue; 173 174 stream.Printf("using $__lldb_local_vars::%s;\n", var_name.AsCString()); 175 } 176 } 177 178 bool ClangExpressionSourceCode::GetText(std::string &text, 179 lldb::LanguageType wrapping_language, 180 bool static_method, 181 ExecutionContext &exe_ctx, 182 bool add_locals) const { 183 const char *target_specific_defines = "typedef signed char BOOL;\n"; 184 std::string module_macros; 185 186 Target *target = exe_ctx.GetTargetPtr(); 187 if (target) { 188 if (target->GetArchitecture().GetMachine() == llvm::Triple::aarch64) { 189 target_specific_defines = "typedef bool BOOL;\n"; 190 } 191 if (target->GetArchitecture().GetMachine() == llvm::Triple::x86_64) { 192 if (lldb::PlatformSP platform_sp = target->GetPlatform()) { 193 static ConstString g_platform_ios_simulator("ios-simulator"); 194 if (platform_sp->GetPluginName() == g_platform_ios_simulator) { 195 target_specific_defines = "typedef bool BOOL;\n"; 196 } 197 } 198 } 199 200 if (ClangModulesDeclVendor *decl_vendor = 201 target->GetClangModulesDeclVendor()) { 202 ClangPersistentVariables *persistent_vars = 203 llvm::cast<ClangPersistentVariables>( 204 target->GetPersistentExpressionStateForLanguage( 205 lldb::eLanguageTypeC)); 206 const ClangModulesDeclVendor::ModuleVector &hand_imported_modules = 207 persistent_vars->GetHandLoadedClangModules(); 208 ClangModulesDeclVendor::ModuleVector modules_for_macros; 209 210 for (ClangModulesDeclVendor::ModuleID module : hand_imported_modules) { 211 modules_for_macros.push_back(module); 212 } 213 214 if (target->GetEnableAutoImportClangModules()) { 215 if (StackFrame *frame = exe_ctx.GetFramePtr()) { 216 if (Block *block = frame->GetFrameBlock()) { 217 SymbolContext sc; 218 219 block->CalculateSymbolContext(&sc); 220 221 if (sc.comp_unit) { 222 StreamString error_stream; 223 224 decl_vendor->AddModulesForCompileUnit( 225 *sc.comp_unit, modules_for_macros, error_stream); 226 } 227 } 228 } 229 } 230 231 decl_vendor->ForEachMacro( 232 modules_for_macros, 233 [&module_macros](const std::string &expansion) -> bool { 234 module_macros.append(expansion); 235 module_macros.append("\n"); 236 return false; 237 }); 238 } 239 } 240 241 StreamString debug_macros_stream; 242 StreamString lldb_local_var_decls; 243 if (StackFrame *frame = exe_ctx.GetFramePtr()) { 244 const SymbolContext &sc = frame->GetSymbolContext( 245 lldb::eSymbolContextCompUnit | lldb::eSymbolContextLineEntry); 246 247 if (sc.comp_unit && sc.line_entry.IsValid()) { 248 DebugMacros *dm = sc.comp_unit->GetDebugMacros(); 249 if (dm) { 250 AddMacroState state(sc.line_entry.file, sc.line_entry.line); 251 AddMacros(dm, sc.comp_unit, state, debug_macros_stream); 252 } 253 } 254 255 if (add_locals) { 256 if (Language::LanguageIsCPlusPlus(frame->GetLanguage())) { 257 if (target->GetInjectLocalVariables(&exe_ctx)) { 258 lldb::VariableListSP var_list_sp = 259 frame->GetInScopeVariableList(false, true); 260 AddLocalVariableDecls(var_list_sp, lldb_local_var_decls); 261 } 262 } 263 } 264 } 265 266 if (m_wrap) { 267 switch (wrapping_language) { 268 default: 269 return false; 270 case lldb::eLanguageTypeC: 271 case lldb::eLanguageTypeC_plus_plus: 272 case lldb::eLanguageTypeObjC: 273 break; 274 } 275 276 StreamString wrap_stream; 277 278 wrap_stream.Printf("%s\n%s\n%s\n%s\n%s\n", module_macros.c_str(), 279 debug_macros_stream.GetData(), g_expression_prefix, 280 target_specific_defines, m_prefix.c_str()); 281 282 // First construct a tagged form of the user expression so we can find it 283 // later: 284 std::string tagged_body; 285 switch (wrapping_language) { 286 default: 287 tagged_body = m_body; 288 break; 289 case lldb::eLanguageTypeC: 290 case lldb::eLanguageTypeC_plus_plus: 291 case lldb::eLanguageTypeObjC: 292 tagged_body.append(c_start_marker); 293 tagged_body.append(m_body); 294 tagged_body.append(c_end_marker); 295 break; 296 } 297 switch (wrapping_language) { 298 default: 299 break; 300 case lldb::eLanguageTypeC: 301 wrap_stream.Printf("void \n" 302 "%s(void *$__lldb_arg) \n" 303 "{ \n" 304 " %s; \n" 305 "%s" 306 "} \n", 307 m_name.c_str(), lldb_local_var_decls.GetData(), 308 tagged_body.c_str()); 309 break; 310 case lldb::eLanguageTypeC_plus_plus: 311 wrap_stream.Printf("void \n" 312 "$__lldb_class::%s(void *$__lldb_arg) \n" 313 "{ \n" 314 " %s; \n" 315 "%s" 316 "} \n", 317 m_name.c_str(), lldb_local_var_decls.GetData(), 318 tagged_body.c_str()); 319 break; 320 case lldb::eLanguageTypeObjC: 321 if (static_method) { 322 wrap_stream.Printf( 323 "@interface $__lldb_objc_class ($__lldb_category) \n" 324 "+(void)%s:(void *)$__lldb_arg; \n" 325 "@end \n" 326 "@implementation $__lldb_objc_class ($__lldb_category) \n" 327 "+(void)%s:(void *)$__lldb_arg \n" 328 "{ \n" 329 "%s" 330 "} \n" 331 "@end \n", 332 m_name.c_str(), m_name.c_str(), tagged_body.c_str()); 333 } else { 334 wrap_stream.Printf( 335 "@interface $__lldb_objc_class ($__lldb_category) \n" 336 "-(void)%s:(void *)$__lldb_arg; \n" 337 "@end \n" 338 "@implementation $__lldb_objc_class ($__lldb_category) \n" 339 "-(void)%s:(void *)$__lldb_arg \n" 340 "{ \n" 341 "%s" 342 "} \n" 343 "@end \n", 344 m_name.c_str(), m_name.c_str(), tagged_body.c_str()); 345 } 346 break; 347 } 348 349 text = wrap_stream.GetString(); 350 } else { 351 text.append(m_body); 352 } 353 354 return true; 355 } 356 357 bool ClangExpressionSourceCode::GetOriginalBodyBounds( 358 std::string transformed_text, lldb::LanguageType wrapping_language, 359 size_t &start_loc, size_t &end_loc) { 360 const char *start_marker; 361 const char *end_marker; 362 363 switch (wrapping_language) { 364 default: 365 return false; 366 case lldb::eLanguageTypeC: 367 case lldb::eLanguageTypeC_plus_plus: 368 case lldb::eLanguageTypeObjC: 369 start_marker = c_start_marker; 370 end_marker = c_end_marker; 371 break; 372 } 373 374 start_loc = transformed_text.find(start_marker); 375 if (start_loc == std::string::npos) 376 return false; 377 start_loc += strlen(start_marker); 378 end_loc = transformed_text.find(end_marker); 379 return end_loc != std::string::npos; 380 } 381