1 //===-- Trace.cpp ---------------------------------------------------------===// 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 "lldb/Target/Trace.h" 10 11 #include "llvm/Support/Format.h" 12 13 #include "lldb/Core/Module.h" 14 #include "lldb/Core/PluginManager.h" 15 #include "lldb/Symbol/Function.h" 16 #include "lldb/Target/ExecutionContext.h" 17 #include "lldb/Target/Process.h" 18 #include "lldb/Target/SectionLoadList.h" 19 #include "lldb/Target/Thread.h" 20 #include "lldb/Utility/LLDBLog.h" 21 #include "lldb/Utility/Stream.h" 22 23 using namespace lldb; 24 using namespace lldb_private; 25 using namespace llvm; 26 27 // Helper structs used to extract the type of a trace session json without 28 // having to parse the entire object. 29 30 struct JSONSimpleTraceSession { 31 std::string type; 32 }; 33 34 namespace llvm { 35 namespace json { 36 37 bool fromJSON(const Value &value, JSONSimpleTraceSession &session, Path path) { 38 json::ObjectMapper o(value, path); 39 return o && o.map("type", session.type); 40 } 41 42 } // namespace json 43 } // namespace llvm 44 45 static Error createInvalidPlugInError(StringRef plugin_name) { 46 return createStringError( 47 std::errc::invalid_argument, 48 "no trace plug-in matches the specified type: \"%s\"", 49 plugin_name.data()); 50 } 51 52 Expected<lldb::TraceSP> 53 Trace::FindPluginForPostMortemProcess(Debugger &debugger, 54 const json::Value &trace_session_file, 55 StringRef session_file_dir) { 56 JSONSimpleTraceSession json_session; 57 json::Path::Root root("traceSession"); 58 if (!json::fromJSON(trace_session_file, json_session, root)) 59 return root.getError(); 60 61 if (auto create_callback = 62 PluginManager::GetTraceCreateCallback(json_session.type)) 63 return create_callback(trace_session_file, session_file_dir, debugger); 64 65 return createInvalidPlugInError(json_session.type); 66 } 67 68 Expected<lldb::TraceSP> Trace::FindPluginForLiveProcess(llvm::StringRef name, 69 Process &process) { 70 if (!process.IsLiveDebugSession()) 71 return createStringError(inconvertibleErrorCode(), 72 "Can't trace non-live processes"); 73 74 if (auto create_callback = 75 PluginManager::GetTraceCreateCallbackForLiveProcess(name)) 76 return create_callback(process); 77 78 return createInvalidPlugInError(name); 79 } 80 81 Expected<StringRef> Trace::FindPluginSchema(StringRef name) { 82 StringRef schema = PluginManager::GetTraceSchema(name); 83 if (!schema.empty()) 84 return schema; 85 86 return createInvalidPlugInError(name); 87 } 88 89 Error Trace::Start(const llvm::json::Value &request) { 90 if (!m_live_process) 91 return createStringError(inconvertibleErrorCode(), 92 "Tracing requires a live process."); 93 return m_live_process->TraceStart(request); 94 } 95 96 Error Trace::Stop() { 97 if (!m_live_process) 98 return createStringError(inconvertibleErrorCode(), 99 "Tracing requires a live process."); 100 return m_live_process->TraceStop(TraceStopRequest(GetPluginName())); 101 } 102 103 Error Trace::Stop(llvm::ArrayRef<lldb::tid_t> tids) { 104 if (!m_live_process) 105 return createStringError(inconvertibleErrorCode(), 106 "Tracing requires a live process."); 107 return m_live_process->TraceStop(TraceStopRequest(GetPluginName(), tids)); 108 } 109 110 Expected<std::string> Trace::GetLiveProcessState() { 111 if (!m_live_process) 112 return createStringError(inconvertibleErrorCode(), 113 "Tracing requires a live process."); 114 return m_live_process->TraceGetState(GetPluginName()); 115 } 116 117 Optional<uint64_t> Trace::GetLiveThreadBinaryDataSize(lldb::tid_t tid, 118 llvm::StringRef kind) { 119 auto it = m_live_thread_data.find(tid); 120 if (it == m_live_thread_data.end()) 121 return None; 122 std::unordered_map<std::string, uint64_t> &single_thread_data = it->second; 123 auto single_thread_data_it = single_thread_data.find(kind.str()); 124 if (single_thread_data_it == single_thread_data.end()) 125 return None; 126 return single_thread_data_it->second; 127 } 128 129 Optional<uint64_t> Trace::GetLiveCoreBinaryDataSize(lldb::core_id_t core_id, 130 llvm::StringRef kind) { 131 auto it = m_live_core_data_sizes.find(core_id); 132 if (it == m_live_core_data_sizes.end()) 133 return None; 134 std::unordered_map<std::string, uint64_t> &single_core_data = it->second; 135 auto single_thread_data_it = single_core_data.find(kind.str()); 136 if (single_thread_data_it == single_core_data.end()) 137 return None; 138 return single_thread_data_it->second; 139 } 140 141 Optional<uint64_t> Trace::GetLiveProcessBinaryDataSize(llvm::StringRef kind) { 142 auto data_it = m_live_process_data.find(kind.str()); 143 if (data_it == m_live_process_data.end()) 144 return None; 145 return data_it->second; 146 } 147 148 Expected<std::vector<uint8_t>> 149 Trace::GetLiveThreadBinaryData(lldb::tid_t tid, llvm::StringRef kind) { 150 if (!m_live_process) 151 return createStringError(inconvertibleErrorCode(), 152 "Tracing requires a live process."); 153 llvm::Optional<uint64_t> size = GetLiveThreadBinaryDataSize(tid, kind); 154 if (!size) 155 return createStringError( 156 inconvertibleErrorCode(), 157 "Tracing data \"%s\" is not available for thread %" PRIu64 ".", 158 kind.data(), tid); 159 160 TraceGetBinaryDataRequest request{GetPluginName().str(), kind.str(), tid, 161 /*core_id=*/None, /*offset=*/0, *size}; 162 return m_live_process->TraceGetBinaryData(request); 163 } 164 165 Expected<std::vector<uint8_t>> 166 Trace::GetLiveCoreBinaryData(lldb::core_id_t core_id, llvm::StringRef kind) { 167 if (!m_live_process) 168 return createStringError(inconvertibleErrorCode(), 169 "Tracing requires a live process."); 170 llvm::Optional<uint64_t> size = GetLiveCoreBinaryDataSize(core_id, kind); 171 if (!size) 172 return createStringError( 173 inconvertibleErrorCode(), 174 "Tracing data \"%s\" is not available for core_id %" PRIu64 ".", 175 kind.data(), core_id); 176 177 TraceGetBinaryDataRequest request{GetPluginName().str(), kind.str(), 178 /*tid=*/None, core_id, 179 /*offset=*/0, *size}; 180 return m_live_process->TraceGetBinaryData(request); 181 } 182 183 Expected<std::vector<uint8_t>> 184 Trace::GetLiveProcessBinaryData(llvm::StringRef kind) { 185 if (!m_live_process) 186 return createStringError(inconvertibleErrorCode(), 187 "Tracing requires a live process."); 188 llvm::Optional<uint64_t> size = GetLiveProcessBinaryDataSize(kind); 189 if (!size) 190 return createStringError( 191 inconvertibleErrorCode(), 192 "Tracing data \"%s\" is not available for the process.", kind.data()); 193 194 TraceGetBinaryDataRequest request{GetPluginName().str(), kind.str(), 195 /*tid=*/None, /*core_id*/ None, 196 /*offset=*/0, *size}; 197 return m_live_process->TraceGetBinaryData(request); 198 } 199 200 const char *Trace::RefreshLiveProcessState() { 201 if (!m_live_process) 202 return nullptr; 203 204 uint32_t new_stop_id = m_live_process->GetStopID(); 205 if (new_stop_id == m_stop_id) 206 return nullptr; 207 208 Log *log = GetLog(LLDBLog::Target); 209 LLDB_LOG(log, "Trace::RefreshLiveProcessState invoked"); 210 211 m_stop_id = new_stop_id; 212 m_live_thread_data.clear(); 213 m_live_refresh_error.reset(); 214 m_live_core_data_sizes.clear(); 215 m_live_core_data.clear(); 216 m_cores.reset(); 217 218 auto HandleError = [&](Error &&err) -> const char * { 219 m_live_refresh_error = toString(std::move(err)); 220 return m_live_refresh_error->c_str(); 221 }; 222 223 Expected<std::string> json_string = GetLiveProcessState(); 224 if (!json_string) 225 return HandleError(json_string.takeError()); 226 227 Expected<TraceGetStateResponse> live_process_state = 228 json::parse<TraceGetStateResponse>(*json_string, "TraceGetStateResponse"); 229 if (!live_process_state) 230 return HandleError(live_process_state.takeError()); 231 232 if (live_process_state->warnings) { 233 for (std::string &warning : *live_process_state->warnings) 234 LLDB_LOG(log, "== Warning when fetching the trace state: {0}", warning); 235 } 236 237 for (const TraceThreadState &thread_state : 238 live_process_state->traced_threads) { 239 for (const TraceBinaryData &item : thread_state.binary_data) 240 m_live_thread_data[thread_state.tid][item.kind] = item.size; 241 } 242 243 LLDB_LOG(log, "== Found {0} threads being traced", 244 live_process_state->traced_threads.size()); 245 246 if (live_process_state->cores) { 247 m_cores.emplace(); 248 for (const TraceCoreState &core_state : *live_process_state->cores) { 249 m_cores->push_back(core_state.core_id); 250 for (const TraceBinaryData &item : core_state.binary_data) 251 m_live_core_data_sizes[core_state.core_id][item.kind] = item.size; 252 } 253 LLDB_LOG(log, "== Found {0} cpu cores being traced", 254 live_process_state->cores->size()); 255 } 256 257 258 for (const TraceBinaryData &item : live_process_state->process_binary_data) 259 m_live_process_data[item.kind] = item.size; 260 261 if (Error err = DoRefreshLiveProcessState(std::move(*live_process_state), 262 *json_string)) 263 return HandleError(std::move(err)); 264 265 return nullptr; 266 } 267 268 Trace::Trace(ArrayRef<ProcessSP> postmortem_processes, 269 Optional<std::vector<lldb::core_id_t>> postmortem_cores) { 270 for (ProcessSP process_sp : postmortem_processes) 271 m_postmortem_processes.push_back(process_sp.get()); 272 m_cores = postmortem_cores; 273 } 274 275 Process *Trace::GetLiveProcess() { return m_live_process; } 276 277 ArrayRef<Process *> Trace::GetPostMortemProcesses() { 278 return m_postmortem_processes; 279 } 280 281 std::vector<Process *> Trace::GetAllProcesses() { 282 if (Process *proc = GetLiveProcess()) 283 return {proc}; 284 return GetPostMortemProcesses(); 285 } 286 287 uint32_t Trace::GetStopID() { 288 RefreshLiveProcessState(); 289 return m_stop_id; 290 } 291 292 llvm::Expected<FileSpec> 293 Trace::GetPostMortemThreadDataFile(lldb::tid_t tid, llvm::StringRef kind) { 294 auto NotFoundError = [&]() { 295 return createStringError( 296 inconvertibleErrorCode(), 297 formatv("The thread with tid={0} doesn't have the tracing data {1}", 298 tid, kind)); 299 }; 300 301 auto it = m_postmortem_thread_data.find(tid); 302 if (it == m_postmortem_thread_data.end()) 303 return NotFoundError(); 304 305 std::unordered_map<std::string, FileSpec> &data_kind_to_file_spec_map = 306 it->second; 307 auto it2 = data_kind_to_file_spec_map.find(kind.str()); 308 if (it2 == data_kind_to_file_spec_map.end()) 309 return NotFoundError(); 310 return it2->second; 311 } 312 313 llvm::Expected<FileSpec> 314 Trace::GetPostMortemCoreDataFile(lldb::core_id_t core_id, 315 llvm::StringRef kind) { 316 auto NotFoundError = [&]() { 317 return createStringError( 318 inconvertibleErrorCode(), 319 formatv("The core with id={0} doesn't have the tracing data {1}", 320 core_id, kind)); 321 }; 322 323 auto it = m_postmortem_core_data.find(core_id); 324 if (it == m_postmortem_core_data.end()) 325 return NotFoundError(); 326 327 std::unordered_map<std::string, FileSpec> &data_kind_to_file_spec_map = 328 it->second; 329 auto it2 = data_kind_to_file_spec_map.find(kind.str()); 330 if (it2 == data_kind_to_file_spec_map.end()) 331 return NotFoundError(); 332 return it2->second; 333 } 334 335 void Trace::SetPostMortemThreadDataFile(lldb::tid_t tid, llvm::StringRef kind, 336 FileSpec file_spec) { 337 m_postmortem_thread_data[tid][kind.str()] = file_spec; 338 } 339 340 void Trace::SetPostMortemCoreDataFile(lldb::core_id_t core_id, 341 llvm::StringRef kind, 342 FileSpec file_spec) { 343 m_postmortem_core_data[core_id][kind.str()] = file_spec; 344 } 345 346 llvm::Error 347 Trace::OnLiveThreadBinaryDataRead(lldb::tid_t tid, llvm::StringRef kind, 348 OnBinaryDataReadCallback callback) { 349 Expected<std::vector<uint8_t>> data = GetLiveThreadBinaryData(tid, kind); 350 if (!data) 351 return data.takeError(); 352 return callback(*data); 353 } 354 355 llvm::Error Trace::OnLiveCoreBinaryDataRead(lldb::core_id_t core_id, 356 llvm::StringRef kind, 357 OnBinaryDataReadCallback callback) { 358 auto core_data_entries = m_live_core_data.find(core_id); 359 if (core_data_entries != m_live_core_data.end()) { 360 auto core_data = core_data_entries->second.find(kind.str()); 361 if (core_data != core_data_entries->second.end()) 362 return callback(core_data->second); 363 } 364 365 Expected<std::vector<uint8_t>> data = GetLiveCoreBinaryData(core_id, kind); 366 if (!data) 367 return data.takeError(); 368 auto it = m_live_core_data[core_id].insert({kind.str(), std::move(*data)}); 369 return callback(it.first->second); 370 } 371 372 llvm::Error Trace::OnDataFileRead(FileSpec file, 373 OnBinaryDataReadCallback callback) { 374 ErrorOr<std::unique_ptr<MemoryBuffer>> trace_or_error = 375 MemoryBuffer::getFile(file.GetPath()); 376 if (std::error_code err = trace_or_error.getError()) 377 return errorCodeToError(err); 378 379 MemoryBuffer &data = **trace_or_error; 380 ArrayRef<uint8_t> array_ref( 381 reinterpret_cast<const uint8_t *>(data.getBufferStart()), 382 data.getBufferSize()); 383 return callback(array_ref); 384 } 385 386 llvm::Error 387 Trace::OnPostMortemThreadBinaryDataRead(lldb::tid_t tid, llvm::StringRef kind, 388 OnBinaryDataReadCallback callback) { 389 Expected<FileSpec> file = GetPostMortemThreadDataFile(tid, kind); 390 if (!file) 391 return file.takeError(); 392 return OnDataFileRead(*file, callback); 393 } 394 395 llvm::Error 396 Trace::OnPostMortemCoreBinaryDataRead(lldb::core_id_t core_id, 397 llvm::StringRef kind, 398 OnBinaryDataReadCallback callback) { 399 Expected<FileSpec> file = GetPostMortemCoreDataFile(core_id, kind); 400 if (!file) 401 return file.takeError(); 402 return OnDataFileRead(*file, callback); 403 } 404 405 llvm::Error Trace::OnThreadBinaryDataRead(lldb::tid_t tid, llvm::StringRef kind, 406 OnBinaryDataReadCallback callback) { 407 RefreshLiveProcessState(); 408 if (m_live_process) 409 return OnLiveThreadBinaryDataRead(tid, kind, callback); 410 else 411 return OnPostMortemThreadBinaryDataRead(tid, kind, callback); 412 } 413 414 llvm::Error 415 Trace::OnCoresBinaryDataRead(const std::set<lldb::core_id_t> core_ids, 416 llvm::StringRef kind, 417 OnCoresBinaryDataReadCallback callback) { 418 DenseMap<core_id_t, ArrayRef<uint8_t>> buffers; 419 420 std::function<Error(std::set<core_id_t>::iterator)> process_core = 421 [&](std::set<core_id_t>::iterator core_id) -> Error { 422 if (core_id == core_ids.end()) 423 return callback(buffers); 424 425 return OnCoreBinaryDataRead(*core_id, kind, 426 [&](ArrayRef<uint8_t> data) -> Error { 427 buffers.try_emplace(*core_id, data); 428 auto next_id = core_id; 429 next_id++; 430 return process_core(next_id); 431 }); 432 }; 433 return process_core(core_ids.begin()); 434 } 435 436 llvm::Error Trace::OnCoreBinaryDataRead(lldb::core_id_t core_id, 437 llvm::StringRef kind, 438 OnBinaryDataReadCallback callback) { 439 RefreshLiveProcessState(); 440 if (m_live_process) 441 return OnLiveCoreBinaryDataRead(core_id, kind, callback); 442 else 443 return OnPostMortemCoreBinaryDataRead(core_id, kind, callback); 444 } 445 446 ArrayRef<lldb::core_id_t> Trace::GetTracedCores() { 447 RefreshLiveProcessState(); 448 if (m_cores) 449 return *m_cores; 450 return {}; 451 } 452