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