brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.5 KiB · 77ef952 Raw
243 lines · cpp
1//===-- StackTraceRequestHandler.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-exception6//7//===----------------------------------------------------------------------===//8 9#include "DAP.h"10#include "EventHelper.h"11#include "JSONUtils.h"12#include "RequestHandler.h"13 14namespace lldb_dap {15 16/// Page size used for reporting addtional frames in the 'stackTrace' request.17static constexpr int StackPageSize = 20;18 19// Fill in the stack frames of the thread.20//21// Threads stacks may contain runtime specific extended backtraces, when22// constructing a stack trace first report the full thread stack trace then23// perform a breadth first traversal of any extended backtrace frames.24//25// For example:26//27// Thread (id=th0) stack=[s0, s1, s2, s3]28//   \ Extended backtrace "libdispatch" Thread (id=th1) stack=[s0, s1]29//     \ Extended backtrace "libdispatch" Thread (id=th2) stack=[s0, s1]30//   \ Extended backtrace "Application Specific Backtrace" Thread (id=th3)31//   stack=[s0, s1, s2]32//33// Which will flatten into:34//35//  0. th0->s036//  1. th0->s137//  2. th0->s238//  3. th0->s339//  4. label - Enqueued from th1, sf=-1, i=-440//  5. th1->s041//  6. th1->s142//  7. label - Enqueued from th243//  8. th2->s044//  9. th2->s145// 10. label - Application Specific Backtrace46// 11. th3->s047// 12. th3->s148// 13. th3->s249//50// s=3,l=3 = [th0->s3, label1, th1->s0]51static bool FillStackFrames(DAP &dap, lldb::SBThread &thread,52                            lldb::SBFormat &frame_format,53                            llvm::json::Array &stack_frames, int64_t &offset,54                            const int64_t start_frame, const int64_t levels,55                            const bool include_all) {56  bool reached_end_of_stack = false;57  for (int64_t i = start_frame;58       static_cast<int64_t>(stack_frames.size()) < levels; i++) {59    if (i == -1) {60      stack_frames.emplace_back(61          CreateExtendedStackFrameLabel(thread, frame_format));62      continue;63    }64 65    lldb::SBFrame frame = thread.GetFrameAtIndex(i);66    if (!frame.IsValid()) {67      offset += thread.GetNumFrames() + 1 /* label between threads */;68      reached_end_of_stack = true;69      break;70    }71 72    stack_frames.emplace_back(CreateStackFrame(dap, frame, frame_format));73  }74 75  if (include_all && reached_end_of_stack) {76    // Check for any extended backtraces.77    for (uint32_t bt = 0;78         bt < thread.GetProcess().GetNumExtendedBacktraceTypes(); bt++) {79      lldb::SBThread backtrace = thread.GetExtendedBacktraceThread(80          thread.GetProcess().GetExtendedBacktraceTypeAtIndex(bt));81      if (!backtrace.IsValid())82        continue;83 84      reached_end_of_stack = FillStackFrames(85          dap, backtrace, frame_format, stack_frames, offset,86          (start_frame - offset) > 0 ? start_frame - offset : -1, levels,87          include_all);88      if (static_cast<int64_t>(stack_frames.size()) >= levels)89        break;90    }91  }92 93  return reached_end_of_stack;94}95 96// "StackTraceRequest": {97//   "allOf": [ { "$ref": "#/definitions/Request" }, {98//     "type": "object",99//     "description": "StackTrace request; value of command field is100//     'stackTrace'. The request returns a stacktrace from the current execution101//     state.", "properties": {102//       "command": {103//         "type": "string",104//         "enum": [ "stackTrace" ]105//       },106//       "arguments": {107//         "$ref": "#/definitions/StackTraceArguments"108//       }109//     },110//     "required": [ "command", "arguments"  ]111//   }]112// },113// "StackTraceArguments": {114//   "type": "object",115//   "description": "Arguments for 'stackTrace' request.",116//   "properties": {117//     "threadId": {118//       "type": "integer",119//       "description": "Retrieve the stacktrace for this thread."120//     },121//     "startFrame": {122//       "type": "integer",123//       "description": "The index of the first frame to return; if omitted124//       frames start at 0."125//     },126//     "levels": {127//       "type": "integer",128//       "description": "The maximum number of frames to return. If levels is129//       not specified or 0, all frames are returned."130//     },131//     "format": {132//       "$ref": "#/definitions/StackFrameFormat",133//       "description": "Specifies details on how to format the stack frames.134//       The attribute is only honored by a debug adapter if the corresponding135//       capability `supportsValueFormattingOptions` is true."136//     }137//  },138//   "required": [ "threadId" ]139// },140// "StackTraceResponse": {141//   "allOf": [ { "$ref": "#/definitions/Response" }, {142//     "type": "object",143//     "description": "Response to `stackTrace` request.",144//     "properties": {145//       "body": {146//         "type": "object",147//         "properties": {148//           "stackFrames": {149//             "type": "array",150//             "items": {151//               "$ref": "#/definitions/StackFrame"152//             },153//             "description": "The frames of the stackframe. If the array has154//             length zero, there are no stackframes available. This means that155//             there is no location information available."156//           },157//           "totalFrames": {158//             "type": "integer",159//             "description": "The total number of frames available in the160//             stack. If omitted or if `totalFrames` is larger than the161//             available frames, a client is expected to request frames until162//             a request returns less frames than requested (which indicates163//             the end of the stack). Returning monotonically increasing164//             `totalFrames` values for subsequent requests can be used to165//             enforce paging in the client."166//           }167//         },168//         "required": [ "stackFrames" ]169//       }170//     },171//     "required": [ "body" ]172//   }]173// }174void StackTraceRequestHandler::operator()(175    const llvm::json::Object &request) const {176  llvm::json::Object response;177  FillResponse(request, response);178  lldb::SBError error;179  const auto *arguments = request.getObject("arguments");180  lldb::SBThread thread = dap.GetLLDBThread(*arguments);181  llvm::json::Array stack_frames;182  llvm::json::Object body;183 184  lldb::SBFormat frame_format = dap.frame_format;185  bool include_all = dap.configuration.displayExtendedBacktrace;186 187  if (const auto *format = arguments->getObject("format")) {188    // Indicates that all stack frames should be included, even those the debug189    // adapter might otherwise hide.190    include_all = GetBoolean(format, "includeAll").value_or(false);191 192    // Parse the properties that have a corresponding format string.193    // FIXME: Support "parameterTypes" and "hex".194    const bool module = GetBoolean(format, "module").value_or(false);195    const bool line = GetBoolean(format, "line").value_or(false);196    const bool parameters = GetBoolean(format, "parameters").value_or(false);197    const bool parameter_names =198        GetBoolean(format, "parameterNames").value_or(false);199    const bool parameter_values =200        GetBoolean(format, "parameterValues").value_or(false);201 202    // Only change the format string if we have to.203    if (module || line || parameters || parameter_names || parameter_values) {204      std::string format_str;205      llvm::raw_string_ostream os(format_str);206 207      if (module)208        os << "{${module.file.basename} }";209 210      if (line)211        os << "{${line.file.basename}:${line.number}:${line.column} }";212 213      if (parameters || parameter_names || parameter_values)214        os << "{${function.name-with-args}}";215      else216        os << "{${function.name-without-args}}";217 218      lldb::SBError error;219      frame_format = lldb::SBFormat(format_str.c_str(), error);220      assert(error.Success());221    }222  }223 224  if (thread.IsValid()) {225    const auto start_frame =226        GetInteger<uint64_t>(arguments, "startFrame").value_or(0);227    const auto levels = GetInteger<uint64_t>(arguments, "levels").value_or(0);228    int64_t offset = 0;229    bool reached_end_of_stack = FillStackFrames(230        dap, thread, frame_format, stack_frames, offset, start_frame,231        levels == 0 ? INT64_MAX : levels, include_all);232    body.try_emplace("totalFrames",233                     start_frame + stack_frames.size() +234                         (reached_end_of_stack ? 0 : StackPageSize));235  }236 237  body.try_emplace("stackFrames", std::move(stack_frames));238  response.try_emplace("body", std::move(body));239  dap.SendJSON(llvm::json::Value(std::move(response)));240}241 242} // namespace lldb_dap243