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 == "this" || var_name == ".block_descriptor") 171 continue; 172 173 stream.Printf("using $__lldb_local_vars::%s;\n", var_name.AsCString()); 174 } 175 } 176 177 bool ClangExpressionSourceCode::GetText(std::string &text, 178 lldb::LanguageType wrapping_language, 179 bool static_method, 180 ExecutionContext &exe_ctx, bool add_locals, 181 llvm::ArrayRef<std::string> modules) const { 182 const char *target_specific_defines = "typedef signed char BOOL;\n"; 183 std::string module_macros; 184 185 Target *target = exe_ctx.GetTargetPtr(); 186 if (target) { 187 if (target->GetArchitecture().GetMachine() == llvm::Triple::aarch64) { 188 target_specific_defines = "typedef bool BOOL;\n"; 189 } 190 if (target->GetArchitecture().GetMachine() == llvm::Triple::x86_64) { 191 if (lldb::PlatformSP platform_sp = target->GetPlatform()) { 192 static ConstString g_platform_ios_simulator("ios-simulator"); 193 if (platform_sp->GetPluginName() == g_platform_ios_simulator) { 194 target_specific_defines = "typedef bool BOOL;\n"; 195 } 196 } 197 } 198 199 if (ClangModulesDeclVendor *decl_vendor = 200 target->GetClangModulesDeclVendor()) { 201 ClangPersistentVariables *persistent_vars = 202 llvm::cast<ClangPersistentVariables>( 203 target->GetPersistentExpressionStateForLanguage( 204 lldb::eLanguageTypeC)); 205 const ClangModulesDeclVendor::ModuleVector &hand_imported_modules = 206 persistent_vars->GetHandLoadedClangModules(); 207 ClangModulesDeclVendor::ModuleVector modules_for_macros; 208 209 for (ClangModulesDeclVendor::ModuleID module : hand_imported_modules) { 210 modules_for_macros.push_back(module); 211 } 212 213 if (target->GetEnableAutoImportClangModules()) { 214 if (StackFrame *frame = exe_ctx.GetFramePtr()) { 215 if (Block *block = frame->GetFrameBlock()) { 216 SymbolContext sc; 217 218 block->CalculateSymbolContext(&sc); 219 220 if (sc.comp_unit) { 221 StreamString error_stream; 222 223 decl_vendor->AddModulesForCompileUnit( 224 *sc.comp_unit, modules_for_macros, error_stream); 225 } 226 } 227 } 228 } 229 230 decl_vendor->ForEachMacro( 231 modules_for_macros, 232 [&module_macros](const std::string &expansion) -> bool { 233 module_macros.append(expansion); 234 module_macros.append("\n"); 235 return false; 236 }); 237 } 238 } 239 240 StreamString debug_macros_stream; 241 StreamString lldb_local_var_decls; 242 if (StackFrame *frame = exe_ctx.GetFramePtr()) { 243 const SymbolContext &sc = frame->GetSymbolContext( 244 lldb::eSymbolContextCompUnit | lldb::eSymbolContextLineEntry); 245 246 if (sc.comp_unit && sc.line_entry.IsValid()) { 247 DebugMacros *dm = sc.comp_unit->GetDebugMacros(); 248 if (dm) { 249 AddMacroState state(sc.line_entry.file, sc.line_entry.line); 250 AddMacros(dm, sc.comp_unit, state, debug_macros_stream); 251 } 252 } 253 254 if (add_locals) { 255 if (Language::LanguageIsCPlusPlus(frame->GetLanguage())) { 256 if (target->GetInjectLocalVariables(&exe_ctx)) { 257 lldb::VariableListSP var_list_sp = 258 frame->GetInScopeVariableList(false, true); 259 AddLocalVariableDecls(var_list_sp, lldb_local_var_decls); 260 } 261 } 262 } 263 } 264 265 if (m_wrap) { 266 switch (wrapping_language) { 267 default: 268 return false; 269 case lldb::eLanguageTypeC: 270 case lldb::eLanguageTypeC_plus_plus: 271 case lldb::eLanguageTypeObjC: 272 break; 273 } 274 275 // Generate a list of @import statements that will import the specified 276 // module into our expression. 277 std::string module_imports; 278 for (const std::string &module : modules) { 279 module_imports.append("@import "); 280 module_imports.append(module); 281 module_imports.append(";\n"); 282 } 283 284 StreamString wrap_stream; 285 286 wrap_stream.Printf("%s\n%s\n%s\n%s\n%s\n", module_macros.c_str(), 287 debug_macros_stream.GetData(), g_expression_prefix, 288 target_specific_defines, m_prefix.c_str()); 289 290 // First construct a tagged form of the user expression so we can find it 291 // later: 292 std::string tagged_body; 293 switch (wrapping_language) { 294 default: 295 tagged_body = m_body; 296 break; 297 case lldb::eLanguageTypeC: 298 case lldb::eLanguageTypeC_plus_plus: 299 case lldb::eLanguageTypeObjC: 300 tagged_body.append(c_start_marker); 301 tagged_body.append(m_body); 302 tagged_body.append(c_end_marker); 303 break; 304 } 305 switch (wrapping_language) { 306 default: 307 break; 308 case lldb::eLanguageTypeC: 309 wrap_stream.Printf("%s" 310 "void \n" 311 "%s(void *$__lldb_arg) \n" 312 "{ \n" 313 " %s; \n" 314 "%s" 315 "} \n", 316 module_imports.c_str(), m_name.c_str(), 317 lldb_local_var_decls.GetData(), tagged_body.c_str()); 318 break; 319 case lldb::eLanguageTypeC_plus_plus: 320 wrap_stream.Printf("%s" 321 "void \n" 322 "$__lldb_class::%s(void *$__lldb_arg) \n" 323 "{ \n" 324 " %s; \n" 325 "%s" 326 "} \n", 327 module_imports.c_str(), m_name.c_str(), 328 lldb_local_var_decls.GetData(), tagged_body.c_str()); 329 break; 330 case lldb::eLanguageTypeObjC: 331 if (static_method) { 332 wrap_stream.Printf( 333 "%s" 334 "@interface $__lldb_objc_class ($__lldb_category) \n" 335 "+(void)%s:(void *)$__lldb_arg; \n" 336 "@end \n" 337 "@implementation $__lldb_objc_class ($__lldb_category) \n" 338 "+(void)%s:(void *)$__lldb_arg \n" 339 "{ \n" 340 "%s" 341 "} \n" 342 "@end \n", 343 module_imports.c_str(), m_name.c_str(), m_name.c_str(), 344 tagged_body.c_str()); 345 } else { 346 wrap_stream.Printf( 347 "%s" 348 "@interface $__lldb_objc_class ($__lldb_category) \n" 349 "-(void)%s:(void *)$__lldb_arg; \n" 350 "@end \n" 351 "@implementation $__lldb_objc_class ($__lldb_category) \n" 352 "-(void)%s:(void *)$__lldb_arg \n" 353 "{ \n" 354 "%s" 355 "} \n" 356 "@end \n", 357 module_imports.c_str(), m_name.c_str(), m_name.c_str(), 358 tagged_body.c_str()); 359 } 360 break; 361 } 362 363 text = wrap_stream.GetString(); 364 } else { 365 text.append(m_body); 366 } 367 368 return true; 369 } 370 371 bool ClangExpressionSourceCode::GetOriginalBodyBounds( 372 std::string transformed_text, lldb::LanguageType wrapping_language, 373 size_t &start_loc, size_t &end_loc) { 374 const char *start_marker; 375 const char *end_marker; 376 377 switch (wrapping_language) { 378 default: 379 return false; 380 case lldb::eLanguageTypeC: 381 case lldb::eLanguageTypeC_plus_plus: 382 case lldb::eLanguageTypeObjC: 383 start_marker = c_start_marker; 384 end_marker = c_end_marker; 385 break; 386 } 387 388 start_loc = transformed_text.find(start_marker); 389 if (start_loc == std::string::npos) 390 return false; 391 start_loc += strlen(start_marker); 392 end_loc = transformed_text.find(end_marker); 393 return end_loc != std::string::npos; 394 } 395