// Copyright 2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

syntax = "proto3";

package google.devtools.clouddebugger.v2;

import "google/devtools/source/v1/source_context.proto";
import "google/protobuf/timestamp.proto";
import "google/protobuf/wrappers.proto";

option cc_enable_arenas = true;
option csharp_namespace = "Google.Cloud.Debugger.V2";
option go_package = "cloud.google.com/go/debugger/apiv2/debuggerpb;debuggerpb";
option java_multiple_files = true;
option java_outer_classname = "DataProto";
option java_package = "com.google.devtools.clouddebugger.v2";
option php_namespace = "Google\\Cloud\\Debugger\\V2";
option ruby_package = "Google::Cloud::Debugger::V2";

// Represents a message with parameters.
message FormatMessage {
  // Format template for the message. The `format` uses placeholders `$0`,
  // `$1`, etc. to reference parameters. `$$` can be used to denote the `$`
  // character.
  //
  // Examples:
  //
  // *   `Failed to load '$0' which helps debug $1 the first time it
  //     is loaded.  Again, $0 is very important.`
  // *   `Please pay $$10 to use $0 instead of $1.`
  string format = 1;

  // Optional parameters to be embedded into the message.
  repeated string parameters = 2;
}

// Represents a contextual status message.
// The message can indicate an error or informational status, and refer to
// specific parts of the containing object.
// For example, the `Breakpoint.status` field can indicate an error referring
// to the `BREAKPOINT_SOURCE_LOCATION` with the message `Location not found`.
message StatusMessage {
  // Enumerates references to which the message applies.
  enum Reference {
    // Status doesn't refer to any particular input.
    UNSPECIFIED = 0;

    // Status applies to the breakpoint and is related to its location.
    BREAKPOINT_SOURCE_LOCATION = 3;

    // Status applies to the breakpoint and is related to its condition.
    BREAKPOINT_CONDITION = 4;

    // Status applies to the breakpoint and is related to its expressions.
    BREAKPOINT_EXPRESSION = 7;

    // Status applies to the breakpoint and is related to its age.
    BREAKPOINT_AGE = 8;

    // Status applies to the entire variable.
    VARIABLE_NAME = 5;

    // Status applies to variable value (variable name is valid).
    VARIABLE_VALUE = 6;
  }

  // Distinguishes errors from informational messages.
  bool is_error = 1;

  // Reference to which the message applies.
  Reference refers_to = 2;

  // Status message text.
  FormatMessage description = 3;
}

// Represents a location in the source code.
message SourceLocation {
  // Path to the source file within the source context of the target binary.
  string path = 1;

  // Line inside the file. The first line in the file has the value `1`.
  int32 line = 2;

  // Column within a line. The first column in a line as the value `1`.
  // Agents that do not support setting breakpoints on specific columns ignore
  // this field.
  int32 column = 3;
}

// Represents a variable or an argument possibly of a compound object type.
// Note how the following variables are represented:
//
// 1) A simple variable:
//
//     int x = 5
//
//     { name: "x", value: "5", type: "int" }  // Captured variable
//
// 2) A compound object:
//
//     struct T {
//         int m1;
//         int m2;
//     };
//     T x = { 3, 7 };
//
//     {  // Captured variable
//         name: "x",
//         type: "T",
//         members { name: "m1", value: "3", type: "int" },
//         members { name: "m2", value: "7", type: "int" }
//     }
//
// 3) A pointer where the pointee was captured:
//
//     T x = { 3, 7 };
//     T* p = &x;
//
//     {   // Captured variable
//         name: "p",
//         type: "T*",
//         value: "0x00500500",
//         members { name: "m1", value: "3", type: "int" },
//         members { name: "m2", value: "7", type: "int" }
//     }
//
// 4) A pointer where the pointee was not captured:
//
//     T* p = new T;
//
//     {   // Captured variable
//         name: "p",
//         type: "T*",
//         value: "0x00400400"
//         status { is_error: true, description { format: "unavailable" } }
//     }
//
// The status should describe the reason for the missing value,
// such as `<optimized out>`, `<inaccessible>`, `<pointers limit reached>`.
//
// Note that a null pointer should not have members.
//
// 5) An unnamed value:
//
//     int* p = new int(7);
//
//     {   // Captured variable
//         name: "p",
//         value: "0x00500500",
//         type: "int*",
//         members { value: "7", type: "int" } }
//
// 6) An unnamed pointer where the pointee was not captured:
//
//     int* p = new int(7);
//     int** pp = &p;
//
//     {  // Captured variable
//         name: "pp",
//         value: "0x00500500",
//         type: "int**",
//         members {
//             value: "0x00400400",
//             type: "int*"
//             status {
//                 is_error: true,
//                 description: { format: "unavailable" } }
//             }
//         }
//     }
//
// To optimize computation, memory and network traffic, variables that
// repeat in the output multiple times can be stored once in a shared
// variable table and be referenced using the `var_table_index` field.  The
// variables stored in the shared table are nameless and are essentially
// a partition of the complete variable. To reconstruct the complete
// variable, merge the referencing variable with the referenced variable.
//
// When using the shared variable table, the following variables:
//
//     T x = { 3, 7 };
//     T* p = &x;
//     T& r = x;
//
//     { name: "x", var_table_index: 3, type: "T" }  // Captured variables
//     { name: "p", value "0x00500500", type="T*", var_table_index: 3 }
//     { name: "r", type="T&", var_table_index: 3 }
//
//     {  // Shared variable table entry #3:
//         members { name: "m1", value: "3", type: "int" },
//         members { name: "m2", value: "7", type: "int" }
//     }
//
// Note that the pointer address is stored with the referencing variable
// and not with the referenced variable. This allows the referenced variable
// to be shared between pointers and references.
//
// The type field is optional. The debugger agent may or may not support it.
message Variable {
  // Name of the variable, if any.
  string name = 1;

  // Simple value of the variable.
  string value = 2;

  // Variable type (e.g. `MyClass`). If the variable is split with
  // `var_table_index`, `type` goes next to `value`. The interpretation of
  // a type is agent specific. It is recommended to include the dynamic type
  // rather than a static type of an object.
  string type = 6;

  // Members contained or pointed to by the variable.
  repeated Variable members = 3;

  // Reference to a variable in the shared variable table. More than
  // one variable can reference the same variable in the table. The
  // `var_table_index` field is an index into `variable_table` in Breakpoint.
  google.protobuf.Int32Value var_table_index = 4;

  // Status associated with the variable. This field will usually stay
  // unset. A status of a single variable only applies to that variable or
  // expression. The rest of breakpoint data still remains valid. Variables
  // might be reported in error state even when breakpoint is not in final
  // state.
  //
  // The message may refer to variable name with `refers_to` set to
  // `VARIABLE_NAME`. Alternatively `refers_to` will be set to `VARIABLE_VALUE`.
  // In either case variable value and members will be unset.
  //
  // Example of error message applied to name: `Invalid expression syntax`.
  //
  // Example of information message applied to value: `Not captured`.
  //
  // Examples of error message applied to value:
  //
  // *   `Malformed string`,
  // *   `Field f not found in class C`
  // *   `Null pointer dereference`
  StatusMessage status = 5;
}

// Represents a stack frame context.
message StackFrame {
  // Demangled function name at the call site.
  string function = 1;

  // Source location of the call site.
  SourceLocation location = 2;

  // Set of arguments passed to this function.
  // Note that this might not be populated for all stack frames.
  repeated Variable arguments = 3;

  // Set of local variables at the stack frame location.
  // Note that this might not be populated for all stack frames.
  repeated Variable locals = 4;
}

// Represents the breakpoint specification, status and results.
message Breakpoint {
  // Actions that can be taken when a breakpoint hits.
  // Agents should reject breakpoints with unsupported or unknown action values.
  enum Action {
    // Capture stack frame and variables and update the breakpoint.
    // The data is only captured once. After that the breakpoint is set
    // in a final state.
    CAPTURE = 0;

    // Log each breakpoint hit. The breakpoint remains active until
    // deleted or expired.
    LOG = 1;
  }

  // Log severity levels.
  enum LogLevel {
    // Information log message.
    INFO = 0;

    // Warning log message.
    WARNING = 1;

    // Error log message.
    ERROR = 2;
  }

  // Breakpoint identifier, unique in the scope of the debuggee.
  string id = 1;

  // Action that the agent should perform when the code at the
  // breakpoint location is hit.
  Action action = 13;

  // Breakpoint source location.
  SourceLocation location = 2;

  // Condition that triggers the breakpoint.
  // The condition is a compound boolean expression composed using expressions
  // in a programming language at the source location.
  string condition = 3;

  // List of read-only expressions to evaluate at the breakpoint location.
  // The expressions are composed using expressions in the programming language
  // at the source location. If the breakpoint action is `LOG`, the evaluated
  // expressions are included in log statements.
  repeated string expressions = 4;

  // Only relevant when action is `LOG`. Defines the message to log when
  // the breakpoint hits. The message may include parameter placeholders `$0`,
  // `$1`, etc. These placeholders are replaced with the evaluated value
  // of the appropriate expression. Expressions not referenced in
  // `log_message_format` are not logged.
  //
  // Example: `Message received, id = $0, count = $1` with
  // `expressions` = `[ message.id, message.count ]`.
  string log_message_format = 14;

  // Indicates the severity of the log. Only relevant when action is `LOG`.
  LogLevel log_level = 15;

  // When true, indicates that this is a final result and the
  // breakpoint state will not change from here on.
  bool is_final_state = 5;

  // Time this breakpoint was created by the server in seconds resolution.
  google.protobuf.Timestamp create_time = 11;

  // Time this breakpoint was finalized as seen by the server in seconds
  // resolution.
  google.protobuf.Timestamp final_time = 12;

  // E-mail address of the user that created this breakpoint
  string user_email = 16;

  // Breakpoint status.
  //
  // The status includes an error flag and a human readable message.
  // This field is usually unset. The message can be either
  // informational or an error message. Regardless, clients should always
  // display the text message back to the user.
  //
  // Error status indicates complete failure of the breakpoint.
  //
  // Example (non-final state): `Still loading symbols...`
  //
  // Examples (final state):
  //
  // *   `Invalid line number` referring to location
  // *   `Field f not found in class C` referring to condition
  StatusMessage status = 10;

  // The stack at breakpoint time, where stack_frames[0] represents the most
  // recently entered function.
  repeated StackFrame stack_frames = 7;

  // Values of evaluated expressions at breakpoint time.
  // The evaluated expressions appear in exactly the same order they
  // are listed in the `expressions` field.
  // The `name` field holds the original expression text, the `value` or
  // `members` field holds the result of the evaluated expression.
  // If the expression cannot be evaluated, the `status` inside the `Variable`
  // will indicate an error and contain the error text.
  repeated Variable evaluated_expressions = 8;

  // The `variable_table` exists to aid with computation, memory and network
  // traffic optimization.  It enables storing a variable once and reference
  // it from multiple variables, including variables stored in the
  // `variable_table` itself.
  // For example, the same `this` object, which may appear at many levels of
  // the stack, can have all of its data stored once in this table.  The
  // stack frame variables then would hold only a reference to it.
  //
  // The variable `var_table_index` field is an index into this repeated field.
  // The stored objects are nameless and get their name from the referencing
  // variable. The effective variable is a merge of the referencing variable
  // and the referenced variable.
  repeated Variable variable_table = 9;

  // A set of custom breakpoint properties, populated by the agent, to be
  // displayed to the user.
  map<string, string> labels = 17;
}

// Represents the debugged application. The application may include one or more
// replicated processes executing the same code. Each of these processes is
// attached with a debugger agent, carrying out the debugging commands.
// Agents attached to the same debuggee identify themselves as such by using
// exactly the same Debuggee message value when registering.
message Debuggee {
  // Unique identifier for the debuggee generated by the controller service.
  string id = 1;

  // Project the debuggee is associated with.
  // Use project number or id when registering a Google Cloud Platform project.
  string project = 2;

  // Uniquifier to further distinguish the application.
  // It is possible that different applications might have identical values in
  // the debuggee message, thus, incorrectly identified as a single application
  // by the Controller service. This field adds salt to further distinguish the
  // application. Agents should consider seeding this field with value that
  // identifies the code, binary, configuration and environment.
  string uniquifier = 3;

  // Human readable description of the debuggee.
  // Including a human-readable project name, environment name and version
  // information is recommended.
  string description = 4;

  // If set to `true`, indicates that Controller service does not detect any
  // activity from the debuggee agents and the application is possibly stopped.
  bool is_inactive = 5;

  // Version ID of the agent.
  // Schema: `domain/language-platform/vmajor.minor` (for example
  // `google.com/java-gcp/v1.1`).
  string agent_version = 6;

  // If set to `true`, indicates that the agent should disable itself and
  // detach from the debuggee.
  bool is_disabled = 7;

  // Human readable message to be displayed to the user about this debuggee.
  // Absence of this field indicates no status. The message can be either
  // informational or an error status.
  StatusMessage status = 8;

  // References to the locations and revisions of the source code used in the
  // deployed application.
  repeated google.devtools.source.v1.SourceContext source_contexts = 9;

  // References to the locations and revisions of the source code used in the
  // deployed application.
  repeated google.devtools.source.v1.ExtendedSourceContext ext_source_contexts = 13 [deprecated = true];

  // A set of custom debuggee properties, populated by the agent, to be
  // displayed to the user.
  map<string, string> labels = 11;
}
