1 //===-- Trace.h -------------------------------------------------*- 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 #ifndef LLDB_TARGET_TRACE_H 10 #define LLDB_TARGET_TRACE_H 11 12 #include <optional> 13 #include <unordered_map> 14 15 #include "llvm/Support/JSON.h" 16 17 #include "lldb/Core/PluginInterface.h" 18 #include "lldb/Target/Thread.h" 19 #include "lldb/Target/TraceCursor.h" 20 #include "lldb/Utility/ArchSpec.h" 21 #include "lldb/Utility/TraceGDBRemotePackets.h" 22 #include "lldb/Utility/UnimplementedError.h" 23 #include "lldb/lldb-private.h" 24 #include "lldb/lldb-types.h" 25 26 namespace lldb_private { 27 28 /// \class Trace Trace.h "lldb/Target/Trace.h" 29 /// A plug-in interface definition class for trace information. 30 /// 31 /// Trace plug-ins allow processor trace information to be loaded into LLDB so 32 /// that the data can be dumped, used for reverse and forward stepping to allow 33 /// introspection into the reason your process crashed or found its way to its 34 /// current state. 35 /// 36 /// Trace information can be loaded into a target without a process to allow 37 /// introspection of the trace information during post mortem analysis, such as 38 /// when loading core files. 39 /// 40 /// Processor trace information can also be fetched through the process 41 /// interfaces during a live debug session if your process supports gathering 42 /// this information. 43 /// 44 /// In order to support live tracing, the name of the plug-in should match the 45 /// name of the tracing type returned by the gdb-remote packet 46 /// \a jLLDBTraceSupported. 47 class Trace : public PluginInterface, 48 public std::enable_shared_from_this<Trace> { 49 public: 50 /// Dump the trace data that this plug-in has access to. 51 /// 52 /// This function will dump all of the trace data for all threads in a user 53 /// readable format. Options for dumping can be added as this API is iterated 54 /// on. 55 /// 56 /// \param[in] s 57 /// A stream object to dump the information to. 58 virtual void Dump(Stream *s) const = 0; 59 60 /// Save the trace to the specified directory, which will be created if 61 /// needed. This will also create a file \a <directory>/trace.json with the 62 /// main properties of the trace session, along with others files which 63 /// contain the actual trace data. The trace.json file can be used later as 64 /// input for the "trace load" command to load the trace in LLDB. 65 /// 66 /// \param[in] directory 67 /// The directory where the trace files will be saved. 68 /// 69 /// \param[in] compact 70 /// Try not to save to disk information irrelevant to the traced processes. 71 /// Each trace plug-in implements this in a different fashion. 72 /// 73 /// \return 74 /// A \a FileSpec pointing to the bundle description file, or an \a 75 /// llvm::Error otherwise. 76 virtual llvm::Expected<FileSpec> SaveToDisk(FileSpec directory, 77 bool compact) = 0; 78 79 /// Find a trace plug-in using JSON data. 80 /// 81 /// When loading trace data from disk, the information for the trace data 82 /// can be contained in multiple files and require plug-in specific 83 /// information about the CPU. Using data like JSON provides an 84 /// easy way to specify all of the settings and information that we will need 85 /// to load trace data into LLDB. This structured data can include: 86 /// - The plug-in name (this allows a specific plug-in to be selected) 87 /// - Architecture or target triple 88 /// - one or more paths to the trace data file on disk 89 /// - cpu trace data 90 /// - thread events or related information 91 /// - shared library load information to use for this trace data that 92 /// allows a target to be created so the trace information can be 93 /// symbolicated so that the trace information can be displayed to the 94 /// user 95 /// - shared library path 96 /// - load address 97 /// - information on how to fetch the shared library 98 /// - path to locally cached file on disk 99 /// - URL to download the file 100 /// - Any information needed to load the trace file 101 /// - CPU information 102 /// - Custom plug-in information needed to decode the trace information 103 /// correctly. 104 /// 105 /// \param[in] debugger 106 /// The debugger instance where new Targets will be created as part of the 107 /// JSON data parsing. 108 /// 109 /// \param[in] bundle_description 110 /// The trace bundle description object describing the trace session. 111 /// 112 /// \param[in] bundle_dir 113 /// The path to the directory that contains the trace bundle. 114 static llvm::Expected<lldb::TraceSP> 115 FindPluginForPostMortemProcess(Debugger &debugger, 116 const llvm::json::Value &bundle_description, 117 llvm::StringRef session_file_dir); 118 119 /// Find a trace plug-in to trace a live process. 120 /// 121 /// \param[in] plugin_name 122 /// Plug-in name to search. 123 /// 124 /// \param[in] process 125 /// Live process to trace. 126 /// 127 /// \return 128 /// A \a TraceSP instance, or an \a llvm::Error if the plug-in name 129 /// doesn't match any registered plug-ins or tracing couldn't be 130 /// started. 131 static llvm::Expected<lldb::TraceSP> 132 FindPluginForLiveProcess(llvm::StringRef plugin_name, Process &process); 133 134 /// Get the schema of a Trace plug-in given its name. 135 /// 136 /// \param[in] plugin_name 137 /// Name of the trace plugin. 138 static llvm::Expected<llvm::StringRef> 139 FindPluginSchema(llvm::StringRef plugin_name); 140 141 /// Load a trace from a trace description file and create Targets, 142 /// Processes and Threads based on the contents of such file. 143 /// 144 /// \param[in] debugger 145 /// The debugger instance where new Targets will be created as part of the 146 /// JSON data parsing. 147 /// 148 /// \param[in] trace_description_file 149 /// The file containing the necessary information to load the trace. 150 /// 151 /// \return 152 /// A \a TraceSP instance, or an \a llvm::Error if loading the trace 153 /// fails. 154 static llvm::Expected<lldb::TraceSP> 155 LoadPostMortemTraceFromFile(Debugger &debugger, 156 const FileSpec &trace_description_file); 157 158 /// Get the command handle for the "process trace start" command. 159 virtual lldb::CommandObjectSP 160 GetProcessTraceStartCommand(CommandInterpreter &interpreter) = 0; 161 162 /// Get the command handle for the "thread trace start" command. 163 virtual lldb::CommandObjectSP 164 GetThreadTraceStartCommand(CommandInterpreter &interpreter) = 0; 165 166 /// \return 167 /// The JSON schema of this Trace plug-in. 168 virtual llvm::StringRef GetSchema() = 0; 169 170 /// Get a \a TraceCursor for the given thread's trace. 171 /// 172 /// \return 173 /// A \a TraceCursorSP. If the thread is not traced or its trace 174 /// information failed to load, an \a llvm::Error is returned. 175 virtual llvm::Expected<lldb::TraceCursorSP> 176 CreateNewCursor(Thread &thread) = 0; 177 178 /// Dump general info about a given thread's trace. Each Trace plug-in 179 /// decides which data to show. 180 /// 181 /// \param[in] thread 182 /// The thread that owns the trace in question. 183 /// 184 /// \param[in] s 185 /// The stream object where the info will be printed printed. 186 /// 187 /// \param[in] verbose 188 /// If \b true, print detailed info 189 /// If \b false, print compact info 190 virtual void DumpTraceInfo(Thread &thread, Stream &s, bool verbose, 191 bool json) = 0; 192 193 /// Check if a thread is currently traced by this object. 194 /// 195 /// \param[in] tid 196 /// The id of the thread in question. 197 /// 198 /// \return 199 /// \b true if the thread is traced by this instance, \b false otherwise. 200 virtual bool IsTraced(lldb::tid_t tid) = 0; 201 202 /// \return 203 /// A description of the parameters to use for the \a Trace::Start method. 204 virtual const char *GetStartConfigurationHelp() = 0; 205 206 /// Start tracing a live process. 207 /// 208 /// \param[in] configuration 209 /// See \a SBTrace::Start(const lldb::SBStructuredData &) for more 210 /// information. 211 /// 212 /// \return 213 /// \a llvm::Error::success if the operation was successful, or 214 /// \a llvm::Error otherwise. 215 virtual llvm::Error Start( 216 StructuredData::ObjectSP configuration = StructuredData::ObjectSP()) = 0; 217 218 /// Start tracing live threads. 219 /// 220 /// \param[in] tids 221 /// Threads to trace. This method tries to trace as many threads as 222 /// possible. 223 /// 224 /// \param[in] configuration 225 /// See \a SBTrace::Start(const lldb::SBThread &, const 226 /// lldb::SBStructuredData &) for more information. 227 /// 228 /// \return 229 /// \a llvm::Error::success if the operation was successful, or 230 /// \a llvm::Error otherwise. 231 virtual llvm::Error Start( 232 llvm::ArrayRef<lldb::tid_t> tids, 233 StructuredData::ObjectSP configuration = StructuredData::ObjectSP()) = 0; 234 235 /// Stop tracing live threads. 236 /// 237 /// \param[in] tids 238 /// The threads to stop tracing on. 239 /// 240 /// \return 241 /// \a llvm::Error::success if the operation was successful, or 242 /// \a llvm::Error otherwise. 243 llvm::Error Stop(llvm::ArrayRef<lldb::tid_t> tids); 244 245 /// Stop tracing all current and future threads of a live process. 246 /// 247 /// \param[in] request 248 /// The information determining which threads or process to stop tracing. 249 /// 250 /// \return 251 /// \a llvm::Error::success if the operation was successful, or 252 /// \a llvm::Error otherwise. 253 llvm::Error Stop(); 254 255 /// \return 256 /// The stop ID of the live process being traced, or an invalid stop ID 257 /// if the trace is in an error or invalid state. 258 uint32_t GetStopID(); 259 260 using OnBinaryDataReadCallback = 261 std::function<llvm::Error(llvm::ArrayRef<uint8_t> data)>; 262 using OnCpusBinaryDataReadCallback = std::function<llvm::Error( 263 const llvm::DenseMap<lldb::cpu_id_t, llvm::ArrayRef<uint8_t>> 264 &cpu_to_data)>; 265 266 /// Fetch binary data associated with a thread, either live or postmortem, and 267 /// pass it to the given callback. The reason of having a callback is to free 268 /// the caller from having to manage the life cycle of the data and to hide 269 /// the different data fetching procedures that exist for live and post mortem 270 /// threads. 271 /// 272 /// The fetched data is not persisted after the callback is invoked. 273 /// 274 /// \param[in] tid 275 /// The tid who owns the data. 276 /// 277 /// \param[in] kind 278 /// The kind of data to read. 279 /// 280 /// \param[in] callback 281 /// The callback to be invoked once the data was successfully read. Its 282 /// return value, which is an \a llvm::Error, is returned by this 283 /// function. 284 /// 285 /// \return 286 /// An \a llvm::Error if the data couldn't be fetched, or the return value 287 /// of the callback, otherwise. 288 llvm::Error OnThreadBinaryDataRead(lldb::tid_t tid, llvm::StringRef kind, 289 OnBinaryDataReadCallback callback); 290 291 /// Fetch binary data associated with a cpu, either live or postmortem, and 292 /// pass it to the given callback. The reason of having a callback is to free 293 /// the caller from having to manage the life cycle of the data and to hide 294 /// the different data fetching procedures that exist for live and post mortem 295 /// cpus. 296 /// 297 /// The fetched data is not persisted after the callback is invoked. 298 /// 299 /// \param[in] cpu_id 300 /// The cpu who owns the data. 301 /// 302 /// \param[in] kind 303 /// The kind of data to read. 304 /// 305 /// \param[in] callback 306 /// The callback to be invoked once the data was successfully read. Its 307 /// return value, which is an \a llvm::Error, is returned by this 308 /// function. 309 /// 310 /// \return 311 /// An \a llvm::Error if the data couldn't be fetched, or the return value 312 /// of the callback, otherwise. 313 llvm::Error OnCpuBinaryDataRead(lldb::cpu_id_t cpu_id, llvm::StringRef kind, 314 OnBinaryDataReadCallback callback); 315 316 /// Similar to \a OnCpuBinaryDataRead but this is able to fetch the same data 317 /// from all cpus at once. 318 llvm::Error OnAllCpusBinaryDataRead(llvm::StringRef kind, 319 OnCpusBinaryDataReadCallback callback); 320 321 /// \return 322 /// All the currently traced processes. 323 std::vector<Process *> GetAllProcesses(); 324 325 /// \return 326 /// The list of cpus being traced. Might be empty depending on the 327 /// plugin. 328 llvm::ArrayRef<lldb::cpu_id_t> GetTracedCpus(); 329 330 /// Helper method for reading a data file and passing its data to the given 331 /// callback. 332 static llvm::Error OnDataFileRead(FileSpec file, 333 OnBinaryDataReadCallback callback); 334 335 protected: 336 /// Get the currently traced live process. 337 /// 338 /// \return 339 /// If it's not a live process, return \a nullptr. 340 Process *GetLiveProcess(); 341 342 /// Get the currently traced postmortem processes. 343 /// 344 /// \return 345 /// If it's not a live process session, return an empty list. 346 llvm::ArrayRef<Process *> GetPostMortemProcesses(); 347 348 /// Dispatcher for live trace data requests with some additional error 349 /// checking. 350 llvm::Expected<std::vector<uint8_t>> 351 GetLiveTraceBinaryData(const TraceGetBinaryDataRequest &request, 352 uint64_t expected_size); 353 354 /// Implementation of \a OnThreadBinaryDataRead() for live threads. 355 llvm::Error OnLiveThreadBinaryDataRead(lldb::tid_t tid, llvm::StringRef kind, 356 OnBinaryDataReadCallback callback); 357 358 /// Implementation of \a OnLiveBinaryDataRead() for live cpus. 359 llvm::Error OnLiveCpuBinaryDataRead(lldb::cpu_id_t cpu, llvm::StringRef kind, 360 OnBinaryDataReadCallback callback); 361 362 /// Implementation of \a OnThreadBinaryDataRead() for post mortem threads. 363 llvm::Error 364 OnPostMortemThreadBinaryDataRead(lldb::tid_t tid, llvm::StringRef kind, 365 OnBinaryDataReadCallback callback); 366 367 /// Implementation of \a OnCpuBinaryDataRead() for post mortem cpus. 368 llvm::Error OnPostMortemCpuBinaryDataRead(lldb::cpu_id_t cpu_id, 369 llvm::StringRef kind, 370 OnBinaryDataReadCallback callback); 371 372 /// Get the file path containing data of a postmortem thread given a data 373 /// identifier. 374 /// 375 /// \param[in] tid 376 /// The thread whose data is requested. 377 /// 378 /// \param[in] kind 379 /// The kind of data requested. 380 /// 381 /// \return 382 /// The file spec containing the requested data, or an \a llvm::Error in 383 /// case of failures. 384 llvm::Expected<FileSpec> GetPostMortemThreadDataFile(lldb::tid_t tid, 385 llvm::StringRef kind); 386 387 /// Get the file path containing data of a postmortem cpu given a data 388 /// identifier. 389 /// 390 /// \param[in] cpu_id 391 /// The cpu whose data is requested. 392 /// 393 /// \param[in] kind 394 /// The kind of data requested. 395 /// 396 /// \return 397 /// The file spec containing the requested data, or an \a llvm::Error in 398 /// case of failures. 399 llvm::Expected<FileSpec> GetPostMortemCpuDataFile(lldb::cpu_id_t cpu_id, 400 llvm::StringRef kind); 401 402 /// Associate a given thread with a data file using a data identifier. 403 /// 404 /// \param[in] tid 405 /// The thread associated with the data file. 406 /// 407 /// \param[in] kind 408 /// The kind of data being registered. 409 /// 410 /// \param[in] file_spec 411 /// The path of the data file. 412 void SetPostMortemThreadDataFile(lldb::tid_t tid, llvm::StringRef kind, 413 FileSpec file_spec); 414 415 /// Associate a given cpu with a data file using a data identifier. 416 /// 417 /// \param[in] cpu_id 418 /// The cpu associated with the data file. 419 /// 420 /// \param[in] kind 421 /// The kind of data being registered. 422 /// 423 /// \param[in] file_spec 424 /// The path of the data file. 425 void SetPostMortemCpuDataFile(lldb::cpu_id_t cpu_id, llvm::StringRef kind, 426 FileSpec file_spec); 427 428 /// Get binary data of a live thread given a data identifier. 429 /// 430 /// \param[in] tid 431 /// The thread whose data is requested. 432 /// 433 /// \param[in] kind 434 /// The kind of data requested. 435 /// 436 /// \return 437 /// A vector of bytes with the requested data, or an \a llvm::Error in 438 /// case of failures. 439 llvm::Expected<std::vector<uint8_t>> 440 GetLiveThreadBinaryData(lldb::tid_t tid, llvm::StringRef kind); 441 442 /// Get binary data of a live cpu given a data identifier. 443 /// 444 /// \param[in] cpu_id 445 /// The cpu whose data is requested. 446 /// 447 /// \param[in] kind 448 /// The kind of data requested. 449 /// 450 /// \return 451 /// A vector of bytes with the requested data, or an \a llvm::Error in 452 /// case of failures. 453 llvm::Expected<std::vector<uint8_t>> 454 GetLiveCpuBinaryData(lldb::cpu_id_t cpu_id, llvm::StringRef kind); 455 456 /// Get binary data of the current process given a data identifier. 457 /// 458 /// \param[in] kind 459 /// The kind of data requested. 460 /// 461 /// \return 462 /// A vector of bytes with the requested data, or an \a llvm::Error in 463 /// case of failures. 464 llvm::Expected<std::vector<uint8_t>> 465 GetLiveProcessBinaryData(llvm::StringRef kind); 466 467 /// Get the size of the data returned by \a GetLiveThreadBinaryData 468 std::optional<uint64_t> GetLiveThreadBinaryDataSize(lldb::tid_t tid, 469 llvm::StringRef kind); 470 471 /// Get the size of the data returned by \a GetLiveCpuBinaryData 472 std::optional<uint64_t> GetLiveCpuBinaryDataSize(lldb::cpu_id_t cpu_id, 473 llvm::StringRef kind); 474 475 /// Get the size of the data returned by \a GetLiveProcessBinaryData 476 std::optional<uint64_t> GetLiveProcessBinaryDataSize(llvm::StringRef kind); 477 478 /// Constructor for post mortem processes 479 Trace(llvm::ArrayRef<lldb::ProcessSP> postmortem_processes, 480 std::optional<std::vector<lldb::cpu_id_t>> postmortem_cpus); 481 482 /// Constructor for a live process 483 Trace(Process &live_process) : m_live_process(&live_process) {} 484 485 /// Start tracing a live process or its threads. 486 /// 487 /// \param[in] request 488 /// JSON object with the information necessary to start tracing. In the 489 /// case of gdb-remote processes, this JSON object should conform to the 490 /// jLLDBTraceStart packet. 491 /// 492 /// \return 493 /// \a llvm::Error::success if the operation was successful, or 494 /// \a llvm::Error otherwise. 495 llvm::Error Start(const llvm::json::Value &request); 496 497 /// Get the current tracing state of a live process and its threads. 498 /// 499 /// \return 500 /// A JSON object string with custom data depending on the trace 501 /// technology, or an \a llvm::Error in case of errors. 502 llvm::Expected<std::string> GetLiveProcessState(); 503 504 /// Method to be overriden by the plug-in to refresh its own state. 505 /// 506 /// This is invoked by RefreshLiveProcessState when a new state is found. 507 /// 508 /// \param[in] state 509 /// The jLLDBTraceGetState response. 510 /// 511 /// \param[in] json_response 512 /// The original JSON response as a string. It might be useful to redecode 513 /// it if it contains custom data for a specific trace plug-in. 514 /// 515 /// \return 516 /// \b Error::success() if this operation succeedes, or an actual error 517 /// otherwise. 518 virtual llvm::Error 519 DoRefreshLiveProcessState(TraceGetStateResponse state, 520 llvm::StringRef json_response) = 0; 521 522 /// Return the list of processes traced by this instance. None of the returned 523 /// pointers are invalid. 524 std::vector<Process *> GetTracedProcesses(); 525 526 /// Method to be invoked by the plug-in to refresh the live process state. It 527 /// will invoked DoRefreshLiveProcessState at some point, which should be 528 /// implemented by the plug-in for custom state handling. 529 /// 530 /// The result is cached through the same process stop. Even in the case of 531 /// errors, it caches the error. 532 /// 533 /// \return 534 /// An error message if this operation failed, or \b nullptr otherwise. 535 const char *RefreshLiveProcessState(); 536 537 private: 538 uint32_t m_stop_id = LLDB_INVALID_STOP_ID; 539 540 /// Process traced by this object if doing live tracing. Otherwise it's null. 541 Process *m_live_process = nullptr; 542 543 /// We package all the data that can change upon process stops to make sure 544 /// this contract is very visible. 545 /// This variable should only be accessed directly by constructores or live 546 /// process data refreshers. 547 struct Storage { 548 /// Portmortem processes traced by this object if doing non-live tracing. 549 /// Otherwise it's empty. 550 std::vector<Process *> postmortem_processes; 551 552 /// These data kinds are returned by lldb-server when fetching the state of 553 /// the tracing session. The size in bytes can be used later for fetching 554 /// the data in batches. 555 /// \{ 556 557 /// tid -> data kind -> size 558 llvm::DenseMap<lldb::tid_t, llvm::DenseMap<ConstString, uint64_t>> 559 live_thread_data; 560 561 /// cpu id -> data kind -> size 562 llvm::DenseMap<lldb::cpu_id_t, llvm::DenseMap<ConstString, uint64_t>> 563 live_cpu_data_sizes; 564 /// cpu id -> data kind -> bytes 565 llvm::DenseMap<lldb::cpu_id_t, 566 llvm::DenseMap<ConstString, std::vector<uint8_t>>> 567 live_cpu_data; 568 569 /// data kind -> size 570 llvm::DenseMap<ConstString, uint64_t> live_process_data; 571 /// \} 572 573 /// The list of cpus being traced. Might be \b std::nullopt depending on the 574 /// plug-in. 575 std::optional<std::vector<lldb::cpu_id_t>> cpus; 576 577 /// Postmortem traces can specific additional data files, which are 578 /// represented in this variable using a data kind identifier for each file. 579 /// \{ 580 581 /// tid -> data kind -> file 582 llvm::DenseMap<lldb::tid_t, llvm::DenseMap<ConstString, FileSpec>> 583 postmortem_thread_data; 584 585 /// cpu id -> data kind -> file 586 llvm::DenseMap<lldb::cpu_id_t, llvm::DenseMap<ConstString, FileSpec>> 587 postmortem_cpu_data; 588 589 /// \} 590 591 std::optional<std::string> live_refresh_error; 592 } m_storage; 593 594 /// Get the storage after refreshing the data in the case of a live process. 595 Storage &GetUpdatedStorage(); 596 }; 597 598 } // namespace lldb_private 599 600 #endif // LLDB_TARGET_TRACE_H 601