1*5ffd83dbSDimitry Andric //===-- InstrumentationRuntimeUBSan.cpp -----------------------------------===// 2*5ffd83dbSDimitry Andric // 3*5ffd83dbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*5ffd83dbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*5ffd83dbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*5ffd83dbSDimitry Andric // 7*5ffd83dbSDimitry Andric //===----------------------------------------------------------------------===// 8*5ffd83dbSDimitry Andric 9*5ffd83dbSDimitry Andric #include "InstrumentationRuntimeUBSan.h" 10*5ffd83dbSDimitry Andric 11*5ffd83dbSDimitry Andric #include "Plugins/Process/Utility/HistoryThread.h" 12*5ffd83dbSDimitry Andric #include "lldb/Breakpoint/StoppointCallbackContext.h" 13*5ffd83dbSDimitry Andric #include "lldb/Core/Debugger.h" 14*5ffd83dbSDimitry Andric #include "lldb/Core/Module.h" 15*5ffd83dbSDimitry Andric #include "lldb/Core/PluginInterface.h" 16*5ffd83dbSDimitry Andric #include "lldb/Core/PluginManager.h" 17*5ffd83dbSDimitry Andric #include "lldb/Core/StreamFile.h" 18*5ffd83dbSDimitry Andric #include "lldb/Core/ValueObject.h" 19*5ffd83dbSDimitry Andric #include "lldb/Expression/UserExpression.h" 20*5ffd83dbSDimitry Andric #include "lldb/Interpreter/CommandReturnObject.h" 21*5ffd83dbSDimitry Andric #include "lldb/Symbol/Symbol.h" 22*5ffd83dbSDimitry Andric #include "lldb/Symbol/SymbolContext.h" 23*5ffd83dbSDimitry Andric #include "lldb/Symbol/Variable.h" 24*5ffd83dbSDimitry Andric #include "lldb/Symbol/VariableList.h" 25*5ffd83dbSDimitry Andric #include "lldb/Target/InstrumentationRuntimeStopInfo.h" 26*5ffd83dbSDimitry Andric #include "lldb/Target/SectionLoadList.h" 27*5ffd83dbSDimitry Andric #include "lldb/Target/StopInfo.h" 28*5ffd83dbSDimitry Andric #include "lldb/Target/Target.h" 29*5ffd83dbSDimitry Andric #include "lldb/Target/Thread.h" 30*5ffd83dbSDimitry Andric #include "lldb/Utility/RegularExpression.h" 31*5ffd83dbSDimitry Andric #include "lldb/Utility/Stream.h" 32*5ffd83dbSDimitry Andric #include <ctype.h> 33*5ffd83dbSDimitry Andric 34*5ffd83dbSDimitry Andric #include <memory> 35*5ffd83dbSDimitry Andric 36*5ffd83dbSDimitry Andric using namespace lldb; 37*5ffd83dbSDimitry Andric using namespace lldb_private; 38*5ffd83dbSDimitry Andric 39*5ffd83dbSDimitry Andric LLDB_PLUGIN_DEFINE(InstrumentationRuntimeUBSan) 40*5ffd83dbSDimitry Andric 41*5ffd83dbSDimitry Andric InstrumentationRuntimeUBSan::~InstrumentationRuntimeUBSan() { Deactivate(); } 42*5ffd83dbSDimitry Andric 43*5ffd83dbSDimitry Andric lldb::InstrumentationRuntimeSP 44*5ffd83dbSDimitry Andric InstrumentationRuntimeUBSan::CreateInstance(const lldb::ProcessSP &process_sp) { 45*5ffd83dbSDimitry Andric return InstrumentationRuntimeSP(new InstrumentationRuntimeUBSan(process_sp)); 46*5ffd83dbSDimitry Andric } 47*5ffd83dbSDimitry Andric 48*5ffd83dbSDimitry Andric void InstrumentationRuntimeUBSan::Initialize() { 49*5ffd83dbSDimitry Andric PluginManager::RegisterPlugin( 50*5ffd83dbSDimitry Andric GetPluginNameStatic(), 51*5ffd83dbSDimitry Andric "UndefinedBehaviorSanitizer instrumentation runtime plugin.", 52*5ffd83dbSDimitry Andric CreateInstance, GetTypeStatic); 53*5ffd83dbSDimitry Andric } 54*5ffd83dbSDimitry Andric 55*5ffd83dbSDimitry Andric void InstrumentationRuntimeUBSan::Terminate() { 56*5ffd83dbSDimitry Andric PluginManager::UnregisterPlugin(CreateInstance); 57*5ffd83dbSDimitry Andric } 58*5ffd83dbSDimitry Andric 59*5ffd83dbSDimitry Andric lldb_private::ConstString InstrumentationRuntimeUBSan::GetPluginNameStatic() { 60*5ffd83dbSDimitry Andric return ConstString("UndefinedBehaviorSanitizer"); 61*5ffd83dbSDimitry Andric } 62*5ffd83dbSDimitry Andric 63*5ffd83dbSDimitry Andric lldb::InstrumentationRuntimeType InstrumentationRuntimeUBSan::GetTypeStatic() { 64*5ffd83dbSDimitry Andric return eInstrumentationRuntimeTypeUndefinedBehaviorSanitizer; 65*5ffd83dbSDimitry Andric } 66*5ffd83dbSDimitry Andric 67*5ffd83dbSDimitry Andric static const char *ub_sanitizer_retrieve_report_data_prefix = R"( 68*5ffd83dbSDimitry Andric extern "C" { 69*5ffd83dbSDimitry Andric void 70*5ffd83dbSDimitry Andric __ubsan_get_current_report_data(const char **OutIssueKind, 71*5ffd83dbSDimitry Andric const char **OutMessage, const char **OutFilename, unsigned *OutLine, 72*5ffd83dbSDimitry Andric unsigned *OutCol, char **OutMemoryAddr); 73*5ffd83dbSDimitry Andric } 74*5ffd83dbSDimitry Andric 75*5ffd83dbSDimitry Andric struct data { 76*5ffd83dbSDimitry Andric const char *issue_kind; 77*5ffd83dbSDimitry Andric const char *message; 78*5ffd83dbSDimitry Andric const char *filename; 79*5ffd83dbSDimitry Andric unsigned line; 80*5ffd83dbSDimitry Andric unsigned col; 81*5ffd83dbSDimitry Andric char *memory_addr; 82*5ffd83dbSDimitry Andric }; 83*5ffd83dbSDimitry Andric )"; 84*5ffd83dbSDimitry Andric 85*5ffd83dbSDimitry Andric static const char *ub_sanitizer_retrieve_report_data_command = R"( 86*5ffd83dbSDimitry Andric data t; 87*5ffd83dbSDimitry Andric __ubsan_get_current_report_data(&t.issue_kind, &t.message, &t.filename, &t.line, 88*5ffd83dbSDimitry Andric &t.col, &t.memory_addr); 89*5ffd83dbSDimitry Andric t; 90*5ffd83dbSDimitry Andric )"; 91*5ffd83dbSDimitry Andric 92*5ffd83dbSDimitry Andric static addr_t RetrieveUnsigned(ValueObjectSP return_value_sp, 93*5ffd83dbSDimitry Andric ProcessSP process_sp, 94*5ffd83dbSDimitry Andric const std::string &expression_path) { 95*5ffd83dbSDimitry Andric return return_value_sp->GetValueForExpressionPath(expression_path.c_str()) 96*5ffd83dbSDimitry Andric ->GetValueAsUnsigned(0); 97*5ffd83dbSDimitry Andric } 98*5ffd83dbSDimitry Andric 99*5ffd83dbSDimitry Andric static std::string RetrieveString(ValueObjectSP return_value_sp, 100*5ffd83dbSDimitry Andric ProcessSP process_sp, 101*5ffd83dbSDimitry Andric const std::string &expression_path) { 102*5ffd83dbSDimitry Andric addr_t ptr = RetrieveUnsigned(return_value_sp, process_sp, expression_path); 103*5ffd83dbSDimitry Andric std::string str; 104*5ffd83dbSDimitry Andric Status error; 105*5ffd83dbSDimitry Andric process_sp->ReadCStringFromMemory(ptr, str, error); 106*5ffd83dbSDimitry Andric return str; 107*5ffd83dbSDimitry Andric } 108*5ffd83dbSDimitry Andric 109*5ffd83dbSDimitry Andric StructuredData::ObjectSP InstrumentationRuntimeUBSan::RetrieveReportData( 110*5ffd83dbSDimitry Andric ExecutionContextRef exe_ctx_ref) { 111*5ffd83dbSDimitry Andric ProcessSP process_sp = GetProcessSP(); 112*5ffd83dbSDimitry Andric if (!process_sp) 113*5ffd83dbSDimitry Andric return StructuredData::ObjectSP(); 114*5ffd83dbSDimitry Andric 115*5ffd83dbSDimitry Andric ThreadSP thread_sp = exe_ctx_ref.GetThreadSP(); 116*5ffd83dbSDimitry Andric StackFrameSP frame_sp = thread_sp->GetSelectedFrame(); 117*5ffd83dbSDimitry Andric ModuleSP runtime_module_sp = GetRuntimeModuleSP(); 118*5ffd83dbSDimitry Andric Target &target = process_sp->GetTarget(); 119*5ffd83dbSDimitry Andric 120*5ffd83dbSDimitry Andric if (!frame_sp) 121*5ffd83dbSDimitry Andric return StructuredData::ObjectSP(); 122*5ffd83dbSDimitry Andric 123*5ffd83dbSDimitry Andric StreamFileSP Stream = target.GetDebugger().GetOutputStreamSP(); 124*5ffd83dbSDimitry Andric 125*5ffd83dbSDimitry Andric EvaluateExpressionOptions options; 126*5ffd83dbSDimitry Andric options.SetUnwindOnError(true); 127*5ffd83dbSDimitry Andric options.SetTryAllThreads(true); 128*5ffd83dbSDimitry Andric options.SetStopOthers(true); 129*5ffd83dbSDimitry Andric options.SetIgnoreBreakpoints(true); 130*5ffd83dbSDimitry Andric options.SetTimeout(process_sp->GetUtilityExpressionTimeout()); 131*5ffd83dbSDimitry Andric options.SetPrefix(ub_sanitizer_retrieve_report_data_prefix); 132*5ffd83dbSDimitry Andric options.SetAutoApplyFixIts(false); 133*5ffd83dbSDimitry Andric options.SetLanguage(eLanguageTypeObjC_plus_plus); 134*5ffd83dbSDimitry Andric 135*5ffd83dbSDimitry Andric ValueObjectSP main_value; 136*5ffd83dbSDimitry Andric ExecutionContext exe_ctx; 137*5ffd83dbSDimitry Andric Status eval_error; 138*5ffd83dbSDimitry Andric frame_sp->CalculateExecutionContext(exe_ctx); 139*5ffd83dbSDimitry Andric ExpressionResults result = UserExpression::Evaluate( 140*5ffd83dbSDimitry Andric exe_ctx, options, ub_sanitizer_retrieve_report_data_command, "", 141*5ffd83dbSDimitry Andric main_value, eval_error); 142*5ffd83dbSDimitry Andric if (result != eExpressionCompleted) { 143*5ffd83dbSDimitry Andric target.GetDebugger().GetAsyncOutputStream()->Printf( 144*5ffd83dbSDimitry Andric "Warning: Cannot evaluate UndefinedBehaviorSanitizer expression:\n%s\n", 145*5ffd83dbSDimitry Andric eval_error.AsCString()); 146*5ffd83dbSDimitry Andric return StructuredData::ObjectSP(); 147*5ffd83dbSDimitry Andric } 148*5ffd83dbSDimitry Andric 149*5ffd83dbSDimitry Andric // Gather the PCs of the user frames in the backtrace. 150*5ffd83dbSDimitry Andric StructuredData::Array *trace = new StructuredData::Array(); 151*5ffd83dbSDimitry Andric auto trace_sp = StructuredData::ObjectSP(trace); 152*5ffd83dbSDimitry Andric for (unsigned I = 0; I < thread_sp->GetStackFrameCount(); ++I) { 153*5ffd83dbSDimitry Andric const Address FCA = 154*5ffd83dbSDimitry Andric thread_sp->GetStackFrameAtIndex(I)->GetFrameCodeAddress(); 155*5ffd83dbSDimitry Andric if (FCA.GetModule() == runtime_module_sp) // Skip PCs from the runtime. 156*5ffd83dbSDimitry Andric continue; 157*5ffd83dbSDimitry Andric 158*5ffd83dbSDimitry Andric lldb::addr_t PC = FCA.GetLoadAddress(&target); 159*5ffd83dbSDimitry Andric trace->AddItem(StructuredData::ObjectSP(new StructuredData::Integer(PC))); 160*5ffd83dbSDimitry Andric } 161*5ffd83dbSDimitry Andric 162*5ffd83dbSDimitry Andric std::string IssueKind = RetrieveString(main_value, process_sp, ".issue_kind"); 163*5ffd83dbSDimitry Andric std::string ErrMessage = RetrieveString(main_value, process_sp, ".message"); 164*5ffd83dbSDimitry Andric std::string Filename = RetrieveString(main_value, process_sp, ".filename"); 165*5ffd83dbSDimitry Andric unsigned Line = RetrieveUnsigned(main_value, process_sp, ".line"); 166*5ffd83dbSDimitry Andric unsigned Col = RetrieveUnsigned(main_value, process_sp, ".col"); 167*5ffd83dbSDimitry Andric uintptr_t MemoryAddr = 168*5ffd83dbSDimitry Andric RetrieveUnsigned(main_value, process_sp, ".memory_addr"); 169*5ffd83dbSDimitry Andric 170*5ffd83dbSDimitry Andric auto *d = new StructuredData::Dictionary(); 171*5ffd83dbSDimitry Andric auto dict_sp = StructuredData::ObjectSP(d); 172*5ffd83dbSDimitry Andric d->AddStringItem("instrumentation_class", "UndefinedBehaviorSanitizer"); 173*5ffd83dbSDimitry Andric d->AddStringItem("description", IssueKind); 174*5ffd83dbSDimitry Andric d->AddStringItem("summary", ErrMessage); 175*5ffd83dbSDimitry Andric d->AddStringItem("filename", Filename); 176*5ffd83dbSDimitry Andric d->AddIntegerItem("line", Line); 177*5ffd83dbSDimitry Andric d->AddIntegerItem("col", Col); 178*5ffd83dbSDimitry Andric d->AddIntegerItem("memory_address", MemoryAddr); 179*5ffd83dbSDimitry Andric d->AddIntegerItem("tid", thread_sp->GetID()); 180*5ffd83dbSDimitry Andric d->AddItem("trace", trace_sp); 181*5ffd83dbSDimitry Andric return dict_sp; 182*5ffd83dbSDimitry Andric } 183*5ffd83dbSDimitry Andric 184*5ffd83dbSDimitry Andric static std::string GetStopReasonDescription(StructuredData::ObjectSP report) { 185*5ffd83dbSDimitry Andric llvm::StringRef stop_reason_description_ref; 186*5ffd83dbSDimitry Andric report->GetAsDictionary()->GetValueForKeyAsString( 187*5ffd83dbSDimitry Andric "description", stop_reason_description_ref); 188*5ffd83dbSDimitry Andric std::string stop_reason_description = 189*5ffd83dbSDimitry Andric std::string(stop_reason_description_ref); 190*5ffd83dbSDimitry Andric 191*5ffd83dbSDimitry Andric if (!stop_reason_description.size()) { 192*5ffd83dbSDimitry Andric stop_reason_description = "Undefined behavior detected"; 193*5ffd83dbSDimitry Andric } else { 194*5ffd83dbSDimitry Andric stop_reason_description[0] = toupper(stop_reason_description[0]); 195*5ffd83dbSDimitry Andric for (unsigned I = 1; I < stop_reason_description.size(); ++I) 196*5ffd83dbSDimitry Andric if (stop_reason_description[I] == '-') 197*5ffd83dbSDimitry Andric stop_reason_description[I] = ' '; 198*5ffd83dbSDimitry Andric } 199*5ffd83dbSDimitry Andric return stop_reason_description; 200*5ffd83dbSDimitry Andric } 201*5ffd83dbSDimitry Andric 202*5ffd83dbSDimitry Andric bool InstrumentationRuntimeUBSan::NotifyBreakpointHit( 203*5ffd83dbSDimitry Andric void *baton, StoppointCallbackContext *context, user_id_t break_id, 204*5ffd83dbSDimitry Andric user_id_t break_loc_id) { 205*5ffd83dbSDimitry Andric assert(baton && "null baton"); 206*5ffd83dbSDimitry Andric if (!baton) 207*5ffd83dbSDimitry Andric return false; ///< false => resume execution. 208*5ffd83dbSDimitry Andric 209*5ffd83dbSDimitry Andric InstrumentationRuntimeUBSan *const instance = 210*5ffd83dbSDimitry Andric static_cast<InstrumentationRuntimeUBSan *>(baton); 211*5ffd83dbSDimitry Andric 212*5ffd83dbSDimitry Andric ProcessSP process_sp = instance->GetProcessSP(); 213*5ffd83dbSDimitry Andric ThreadSP thread_sp = context->exe_ctx_ref.GetThreadSP(); 214*5ffd83dbSDimitry Andric if (!process_sp || !thread_sp || 215*5ffd83dbSDimitry Andric process_sp != context->exe_ctx_ref.GetProcessSP()) 216*5ffd83dbSDimitry Andric return false; 217*5ffd83dbSDimitry Andric 218*5ffd83dbSDimitry Andric if (process_sp->GetModIDRef().IsLastResumeForUserExpression()) 219*5ffd83dbSDimitry Andric return false; 220*5ffd83dbSDimitry Andric 221*5ffd83dbSDimitry Andric StructuredData::ObjectSP report = 222*5ffd83dbSDimitry Andric instance->RetrieveReportData(context->exe_ctx_ref); 223*5ffd83dbSDimitry Andric 224*5ffd83dbSDimitry Andric if (report) { 225*5ffd83dbSDimitry Andric thread_sp->SetStopInfo( 226*5ffd83dbSDimitry Andric InstrumentationRuntimeStopInfo::CreateStopReasonWithInstrumentationData( 227*5ffd83dbSDimitry Andric *thread_sp, GetStopReasonDescription(report), report)); 228*5ffd83dbSDimitry Andric return true; 229*5ffd83dbSDimitry Andric } 230*5ffd83dbSDimitry Andric 231*5ffd83dbSDimitry Andric return false; 232*5ffd83dbSDimitry Andric } 233*5ffd83dbSDimitry Andric 234*5ffd83dbSDimitry Andric const RegularExpression & 235*5ffd83dbSDimitry Andric InstrumentationRuntimeUBSan::GetPatternForRuntimeLibrary() { 236*5ffd83dbSDimitry Andric static RegularExpression regex(llvm::StringRef("libclang_rt\\.(a|t|ub)san_")); 237*5ffd83dbSDimitry Andric return regex; 238*5ffd83dbSDimitry Andric } 239*5ffd83dbSDimitry Andric 240*5ffd83dbSDimitry Andric bool InstrumentationRuntimeUBSan::CheckIfRuntimeIsValid( 241*5ffd83dbSDimitry Andric const lldb::ModuleSP module_sp) { 242*5ffd83dbSDimitry Andric static ConstString ubsan_test_sym("__ubsan_on_report"); 243*5ffd83dbSDimitry Andric const Symbol *symbol = module_sp->FindFirstSymbolWithNameAndType( 244*5ffd83dbSDimitry Andric ubsan_test_sym, lldb::eSymbolTypeAny); 245*5ffd83dbSDimitry Andric return symbol != nullptr; 246*5ffd83dbSDimitry Andric } 247*5ffd83dbSDimitry Andric 248*5ffd83dbSDimitry Andric // FIXME: Factor out all the logic we have in common with the {a,t}san plugins. 249*5ffd83dbSDimitry Andric void InstrumentationRuntimeUBSan::Activate() { 250*5ffd83dbSDimitry Andric if (IsActive()) 251*5ffd83dbSDimitry Andric return; 252*5ffd83dbSDimitry Andric 253*5ffd83dbSDimitry Andric ProcessSP process_sp = GetProcessSP(); 254*5ffd83dbSDimitry Andric if (!process_sp) 255*5ffd83dbSDimitry Andric return; 256*5ffd83dbSDimitry Andric 257*5ffd83dbSDimitry Andric ModuleSP runtime_module_sp = GetRuntimeModuleSP(); 258*5ffd83dbSDimitry Andric 259*5ffd83dbSDimitry Andric ConstString symbol_name("__ubsan_on_report"); 260*5ffd83dbSDimitry Andric const Symbol *symbol = runtime_module_sp->FindFirstSymbolWithNameAndType( 261*5ffd83dbSDimitry Andric symbol_name, eSymbolTypeCode); 262*5ffd83dbSDimitry Andric 263*5ffd83dbSDimitry Andric if (symbol == nullptr) 264*5ffd83dbSDimitry Andric return; 265*5ffd83dbSDimitry Andric 266*5ffd83dbSDimitry Andric if (!symbol->ValueIsAddress() || !symbol->GetAddressRef().IsValid()) 267*5ffd83dbSDimitry Andric return; 268*5ffd83dbSDimitry Andric 269*5ffd83dbSDimitry Andric Target &target = process_sp->GetTarget(); 270*5ffd83dbSDimitry Andric addr_t symbol_address = symbol->GetAddressRef().GetOpcodeLoadAddress(&target); 271*5ffd83dbSDimitry Andric 272*5ffd83dbSDimitry Andric if (symbol_address == LLDB_INVALID_ADDRESS) 273*5ffd83dbSDimitry Andric return; 274*5ffd83dbSDimitry Andric 275*5ffd83dbSDimitry Andric Breakpoint *breakpoint = 276*5ffd83dbSDimitry Andric process_sp->GetTarget() 277*5ffd83dbSDimitry Andric .CreateBreakpoint(symbol_address, /*internal=*/true, 278*5ffd83dbSDimitry Andric /*hardware=*/false) 279*5ffd83dbSDimitry Andric .get(); 280*5ffd83dbSDimitry Andric breakpoint->SetCallback(InstrumentationRuntimeUBSan::NotifyBreakpointHit, 281*5ffd83dbSDimitry Andric this, true); 282*5ffd83dbSDimitry Andric breakpoint->SetBreakpointKind("undefined-behavior-sanitizer-report"); 283*5ffd83dbSDimitry Andric SetBreakpointID(breakpoint->GetID()); 284*5ffd83dbSDimitry Andric 285*5ffd83dbSDimitry Andric SetActive(true); 286*5ffd83dbSDimitry Andric } 287*5ffd83dbSDimitry Andric 288*5ffd83dbSDimitry Andric void InstrumentationRuntimeUBSan::Deactivate() { 289*5ffd83dbSDimitry Andric SetActive(false); 290*5ffd83dbSDimitry Andric 291*5ffd83dbSDimitry Andric auto BID = GetBreakpointID(); 292*5ffd83dbSDimitry Andric if (BID == LLDB_INVALID_BREAK_ID) 293*5ffd83dbSDimitry Andric return; 294*5ffd83dbSDimitry Andric 295*5ffd83dbSDimitry Andric if (ProcessSP process_sp = GetProcessSP()) { 296*5ffd83dbSDimitry Andric process_sp->GetTarget().RemoveBreakpointByID(BID); 297*5ffd83dbSDimitry Andric SetBreakpointID(LLDB_INVALID_BREAK_ID); 298*5ffd83dbSDimitry Andric } 299*5ffd83dbSDimitry Andric } 300*5ffd83dbSDimitry Andric 301*5ffd83dbSDimitry Andric lldb::ThreadCollectionSP 302*5ffd83dbSDimitry Andric InstrumentationRuntimeUBSan::GetBacktracesFromExtendedStopInfo( 303*5ffd83dbSDimitry Andric StructuredData::ObjectSP info) { 304*5ffd83dbSDimitry Andric ThreadCollectionSP threads; 305*5ffd83dbSDimitry Andric threads = std::make_shared<ThreadCollection>(); 306*5ffd83dbSDimitry Andric 307*5ffd83dbSDimitry Andric ProcessSP process_sp = GetProcessSP(); 308*5ffd83dbSDimitry Andric 309*5ffd83dbSDimitry Andric if (info->GetObjectForDotSeparatedPath("instrumentation_class") 310*5ffd83dbSDimitry Andric ->GetStringValue() != "UndefinedBehaviorSanitizer") 311*5ffd83dbSDimitry Andric return threads; 312*5ffd83dbSDimitry Andric 313*5ffd83dbSDimitry Andric std::vector<lldb::addr_t> PCs; 314*5ffd83dbSDimitry Andric auto trace = info->GetObjectForDotSeparatedPath("trace")->GetAsArray(); 315*5ffd83dbSDimitry Andric trace->ForEach([&PCs](StructuredData::Object *PC) -> bool { 316*5ffd83dbSDimitry Andric PCs.push_back(PC->GetAsInteger()->GetValue()); 317*5ffd83dbSDimitry Andric return true; 318*5ffd83dbSDimitry Andric }); 319*5ffd83dbSDimitry Andric 320*5ffd83dbSDimitry Andric if (PCs.empty()) 321*5ffd83dbSDimitry Andric return threads; 322*5ffd83dbSDimitry Andric 323*5ffd83dbSDimitry Andric StructuredData::ObjectSP thread_id_obj = 324*5ffd83dbSDimitry Andric info->GetObjectForDotSeparatedPath("tid"); 325*5ffd83dbSDimitry Andric tid_t tid = thread_id_obj ? thread_id_obj->GetIntegerValue() : 0; 326*5ffd83dbSDimitry Andric 327*5ffd83dbSDimitry Andric HistoryThread *history_thread = new HistoryThread(*process_sp, tid, PCs); 328*5ffd83dbSDimitry Andric ThreadSP new_thread_sp(history_thread); 329*5ffd83dbSDimitry Andric std::string stop_reason_description = GetStopReasonDescription(info); 330*5ffd83dbSDimitry Andric new_thread_sp->SetName(stop_reason_description.c_str()); 331*5ffd83dbSDimitry Andric 332*5ffd83dbSDimitry Andric // Save this in the Process' ExtendedThreadList so a strong pointer retains 333*5ffd83dbSDimitry Andric // the object 334*5ffd83dbSDimitry Andric process_sp->GetExtendedThreadList().AddThread(new_thread_sp); 335*5ffd83dbSDimitry Andric threads->AddThread(new_thread_sp); 336*5ffd83dbSDimitry Andric 337*5ffd83dbSDimitry Andric return threads; 338*5ffd83dbSDimitry Andric } 339