1#!/usr/bin/env python3 2# -*- coding: utf-8 -*- 3""" 4Copyright (c) 2024 Huawei Device Co., Ltd. 5Licensed under the Apache License, Version 2.0 (the "License"); 6you may not use this file except in compliance with the License. 7You may obtain a copy of the License at 8 9 http://www.apache.org/licenses/LICENSE-2.0 10 11Unless required by applicable law or agreed to in writing, software 12distributed under the License is distributed on an "AS IS" BASIS, 13WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14See the License for the specific language governing permissions and 15limitations under the License. 16 17Description: Python CDP Debugger. 18""" 19 20from dataclasses import dataclass, field 21from enum import Enum 22from typing import Optional, List 23 24 25@dataclass 26class EnableAccelerateLaunchParams: 27 options = ['enableLaunchAccelerate'] 28 max_scripts_cache_size: float = 1e7 29 30 31@dataclass 32class SaveAllPossibleBreakpointsParams: 33 locations: dict 34 35 36@dataclass 37class DropFrameParams: 38 dropped_depth: int = 1 39 40 41@dataclass 42class ReplyNativeCallingParams: 43 user_code: bool = True 44 45 46@dataclass 47class SetMixedDebugEnabledParams: 48 enabled: bool 49 mixed_stack_enabled: bool 50 51 52@dataclass 53class SmartStepIntoParams: 54 url: str 55 line_number: int 56 57 58@dataclass 59class PauseOnExceptionsState(Enum): 60 ALL = 'all' 61 NONE = 'none' 62 CAUGHT = 'caught' 63 UNCAUGHT = 'uncaught' 64 65 66@dataclass 67class EvaluateOnCallFrameParams: 68 expression: str 69 call_frame_id: int = 0 70 object_group: str = "console" 71 include_command_line_api: bool = True 72 silent: bool = True 73 74 75@dataclass 76class BreakLocationUrl: 77 url: str 78 line_number: int 79 column_number: Optional[int] = 0 80 condition: Optional[str] = None 81 82 def to_json(self): 83 json = {'url': self.url, 84 'lineNumber': self.line_number, 85 'columnNumber': self.column_number} 86 if self.condition is not None: 87 json['condition'] = self.condition 88 return json 89 90 91@dataclass 92class SymbolicBreakpoint: 93 functionName: str 94 95 def to_json(self): 96 return {'functionName': self.functionName} 97 98 99@dataclass 100class RemoveBreakpointsUrl: 101 url: str = "" 102 103 104@dataclass 105class SetBreakpointsLocations: 106 locations: list = field(default_factory=list) 107 108 109@dataclass 110class SymbolicBreakpoints: 111 SymbolicBreakpoints: List[SymbolicBreakpoint] = field(default_factory=list) 112 113 114def enable(params: EnableAccelerateLaunchParams | None): 115 command = {'method': 'Debugger.enable'} 116 if params is not None: 117 command['params'] = { 118 'options': params.options, 119 'maxScriptsCacheSize': params.max_scripts_cache_size 120 } 121 return command 122 123 124def resume(): 125 command = {'method': 'Debugger.resume'} 126 return command 127 128 129def remove_breakpoints_by_url(params: RemoveBreakpointsUrl): 130 command = {'method': 'Debugger.removeBreakpointsByUrl', 131 'params': {'url': params.url}} 132 return command 133 134 135def get_possible_and_set_breakpoint_by_url(params: SetBreakpointsLocations): 136 locations = [] 137 for location in params.locations: 138 locations.append(location.to_json()) 139 command = {'method': 'Debugger.getPossibleAndSetBreakpointByUrl', 140 'params': {'locations': locations}} 141 return command 142 143 144def set_symbolic_breakpoints(params: SymbolicBreakpoints): 145 symbolicBreakpoints = [] 146 for symbolicBreakpoint in params.SymbolicBreakpoints: 147 symbolicBreakpoints.append(symbolicBreakpoint.to_json()) 148 command = {'method': 'Debugger.setSymbolicBreakpoints', 149 'params': {'symbolicBreakpoints': symbolicBreakpoints}} 150 return command 151 152 153def remove_symbolic_breakpoints(params: SymbolicBreakpoints): 154 symbolicBreakpoints = [] 155 for symbolicBreakpoint in params.SymbolicBreakpoints: 156 symbolicBreakpoints.append(symbolicBreakpoint.to_json()) 157 command = {'method': 'Debugger.removeSymbolicBreakpoints', 158 'params': {'symbolicBreakpoints': symbolicBreakpoints}} 159 return command 160 161 162def step_over(): 163 command = {'method': 'Debugger.stepOver'} 164 return command 165 166 167def step_into(): 168 command = {'method': 'Debugger.stepInto'} 169 return command 170 171 172def step_out(): 173 command = {'method': 'Debugger.stepOut'} 174 return command 175 176 177def disable(): 178 command = {'method': 'Debugger.disable'} 179 return command 180 181 182def set_pause_on_exceptions(params: PauseOnExceptionsState): 183 command = {'method': 'Debugger.setPauseOnExceptions', 184 'params': {'state': params.value}} 185 return command 186 187 188def evaluate_on_call_frame(params: EvaluateOnCallFrameParams): 189 command = {'method': 'Debugger.evaluateOnCallFrame', 190 'params': { 191 'callFrameId': str(params.call_frame_id), 192 'expression': params.expression, 193 'includeCommandLineAPI': params.include_command_line_api, 194 'objectGroup': params.object_group, 195 'silent': params.silent}} 196 return command 197 198 199def pause(): 200 command = {'method': 'Debugger.pause'} 201 return command 202 203 204def set_mixed_debug_enabled(params: SetMixedDebugEnabledParams): 205 command = {'method': 'Debugger.setMixedDebugEnabled', 206 'params': {'enabled': params.enabled, 'mixedStackEnabled': params.mixed_stack_enabled}} 207 return command 208 209 210def reply_native_calling(params: ReplyNativeCallingParams): 211 command = {'method': 'Debugger.replyNativeCalling', 212 'params': {'userCode': params.user_code}} 213 return command 214 215 216def drop_frame(params: DropFrameParams): 217 command = {'method': 'Debugger.dropFrame', 218 'params': {'droppedDepth': params.dropped_depth}} 219 return command 220 221 222def smart_step_into(params: SmartStepIntoParams): 223 command = {'method': 'Debugger.smartStepInto', 224 'params': {'url': params.url, 'lineNumber': params.line_number}} 225 return command 226 227 228def save_all_possible_breakpoints(params: SaveAllPossibleBreakpointsParams): 229 locations = {} 230 for key, value in params.locations.items(): 231 positions = [] 232 for pos in value: 233 if isinstance(pos, int): 234 positions.append({"lineNumber": pos, "colomnNumber": 0}) 235 else: 236 positions.append({"lineNumber": pos[0], "colomnNumber": pos[1]}) 237 locations[key] = positions 238 command = {'method': 'Debugger.saveAllPossibleBreakpoints', 239 'params': {'locations': locations}} 240 return command