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, bool add_locals, 182 llvm::ArrayRef<std::string> modules) 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 // Generate a list of @import statements that will import the specified 277 // module into our expression. 278 std::string module_imports; 279 for (const std::string &module : modules) { 280 module_imports.append("@import "); 281 module_imports.append(module); 282 module_imports.append(";\n"); 283 } 284 285 StreamString wrap_stream; 286 287 wrap_stream.Printf("%s\n%s\n%s\n%s\n%s\n", module_macros.c_str(), 288 debug_macros_stream.GetData(), g_expression_prefix, 289 target_specific_defines, m_prefix.c_str()); 290 291 // First construct a tagged form of the user expression so we can find it 292 // later: 293 std::string tagged_body; 294 switch (wrapping_language) { 295 default: 296 tagged_body = m_body; 297 break; 298 case lldb::eLanguageTypeC: 299 case lldb::eLanguageTypeC_plus_plus: 300 case lldb::eLanguageTypeObjC: 301 tagged_body.append(c_start_marker); 302 tagged_body.append(m_body); 303 tagged_body.append(c_end_marker); 304 break; 305 } 306 switch (wrapping_language) { 307 default: 308 break; 309 case lldb::eLanguageTypeC: 310 wrap_stream.Printf("%s" 311 "void \n" 312 "%s(void *$__lldb_arg) \n" 313 "{ \n" 314 " %s; \n" 315 "%s" 316 "} \n", 317 module_imports.c_str(), m_name.c_str(), 318 lldb_local_var_decls.GetData(), tagged_body.c_str()); 319 break; 320 case lldb::eLanguageTypeC_plus_plus: 321 wrap_stream.Printf("%s" 322 "void \n" 323 "$__lldb_class::%s(void *$__lldb_arg) \n" 324 "{ \n" 325 " %s; \n" 326 "%s" 327 "} \n", 328 module_imports.c_str(), m_name.c_str(), 329 lldb_local_var_decls.GetData(), tagged_body.c_str()); 330 break; 331 case lldb::eLanguageTypeObjC: 332 if (static_method) { 333 wrap_stream.Printf( 334 "%s" 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 module_imports.c_str(), m_name.c_str(), m_name.c_str(), 345 tagged_body.c_str()); 346 } else { 347 wrap_stream.Printf( 348 "%s" 349 "@interface $__lldb_objc_class ($__lldb_category) \n" 350 "-(void)%s:(void *)$__lldb_arg; \n" 351 "@end \n" 352 "@implementation $__lldb_objc_class ($__lldb_category) \n" 353 "-(void)%s:(void *)$__lldb_arg \n" 354 "{ \n" 355 "%s" 356 "} \n" 357 "@end \n", 358 module_imports.c_str(), m_name.c_str(), m_name.c_str(), 359 tagged_body.c_str()); 360 } 361 break; 362 } 363 364 text = wrap_stream.GetString(); 365 } else { 366 text.append(m_body); 367 } 368 369 return true; 370 } 371 372 bool ClangExpressionSourceCode::GetOriginalBodyBounds( 373 std::string transformed_text, lldb::LanguageType wrapping_language, 374 size_t &start_loc, size_t &end_loc) { 375 const char *start_marker; 376 const char *end_marker; 377 378 switch (wrapping_language) { 379 default: 380 return false; 381 case lldb::eLanguageTypeC: 382 case lldb::eLanguageTypeC_plus_plus: 383 case lldb::eLanguageTypeObjC: 384 start_marker = c_start_marker; 385 end_marker = c_end_marker; 386 break; 387 } 388 389 start_loc = transformed_text.find(start_marker); 390 if (start_loc == std::string::npos) 391 return false; 392 start_loc += strlen(start_marker); 393 end_loc = transformed_text.find(end_marker); 394 return end_loc != std::string::npos; 395 } 396