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