1 //===-- BreakpointIDList.cpp ------------------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 // C Includes 11 // C++ Includes 12 // Other libraries and framework includes 13 // Project includes 14 #include "lldb/Breakpoint/BreakpointIDList.h" 15 16 #include "lldb/Breakpoint/Breakpoint.h" 17 #include "lldb/Breakpoint/BreakpointLocation.h" 18 #include "lldb/Interpreter/CommandReturnObject.h" 19 #include "lldb/Interpreter/Args.h" 20 #include "lldb/Target/Target.h" 21 22 using namespace lldb; 23 using namespace lldb_private; 24 25 //---------------------------------------------------------------------- 26 // class BreakpointIDList 27 //---------------------------------------------------------------------- 28 29 BreakpointIDList::BreakpointIDList () : 30 m_invalid_id (LLDB_INVALID_BREAK_ID, LLDB_INVALID_BREAK_ID) 31 { 32 } 33 34 BreakpointIDList::~BreakpointIDList() = default; 35 36 size_t 37 BreakpointIDList::GetSize() 38 { 39 return m_breakpoint_ids.size(); 40 } 41 42 BreakpointID & 43 BreakpointIDList::GetBreakpointIDAtIndex(size_t index) 44 { 45 return ((index < m_breakpoint_ids.size()) ? m_breakpoint_ids[index] : m_invalid_id); 46 } 47 48 bool 49 BreakpointIDList::RemoveBreakpointIDAtIndex (size_t index) 50 { 51 if (index >= m_breakpoint_ids.size()) 52 return false; 53 54 m_breakpoint_ids.erase (m_breakpoint_ids.begin() + index); 55 return true; 56 } 57 58 void 59 BreakpointIDList::Clear() 60 { 61 m_breakpoint_ids.clear (); 62 } 63 64 bool 65 BreakpointIDList::AddBreakpointID (BreakpointID bp_id) 66 { 67 m_breakpoint_ids.push_back (bp_id); 68 69 return true; // We don't do any verification in this function, so always return true. 70 } 71 72 bool 73 BreakpointIDList::AddBreakpointID (const char *bp_id_str) 74 { 75 BreakpointID temp_bp_id; 76 break_id_t bp_id; 77 break_id_t loc_id; 78 79 bool success = BreakpointID::ParseCanonicalReference (bp_id_str, &bp_id, &loc_id); 80 81 if (success) 82 { 83 temp_bp_id.SetID (bp_id, loc_id); 84 m_breakpoint_ids.push_back (temp_bp_id); 85 } 86 87 return success; 88 } 89 90 bool 91 BreakpointIDList::FindBreakpointID (BreakpointID &bp_id, size_t *position) 92 { 93 for (size_t i = 0; i < m_breakpoint_ids.size(); ++i) 94 { 95 BreakpointID tmp_id = m_breakpoint_ids[i]; 96 if (tmp_id.GetBreakpointID() == bp_id.GetBreakpointID() 97 && tmp_id.GetLocationID() == bp_id.GetLocationID()) 98 { 99 *position = i; 100 return true; 101 } 102 } 103 104 return false; 105 } 106 107 bool 108 BreakpointIDList::FindBreakpointID (const char *bp_id_str, size_t *position) 109 { 110 BreakpointID temp_bp_id; 111 break_id_t bp_id; 112 break_id_t loc_id; 113 114 if (BreakpointID::ParseCanonicalReference (bp_id_str, &bp_id, &loc_id)) 115 { 116 temp_bp_id.SetID (bp_id, loc_id); 117 return FindBreakpointID (temp_bp_id, position); 118 } 119 else 120 return false; 121 } 122 123 void 124 BreakpointIDList::InsertStringArray (const char **string_array, size_t array_size, CommandReturnObject &result) 125 { 126 if (string_array == nullptr) 127 return; 128 129 for (uint32_t i = 0; i < array_size; ++i) 130 { 131 break_id_t bp_id; 132 break_id_t loc_id; 133 134 if (BreakpointID::ParseCanonicalReference (string_array[i], &bp_id, &loc_id)) 135 { 136 if (bp_id != LLDB_INVALID_BREAK_ID) 137 { 138 BreakpointID temp_bp_id(bp_id, loc_id); 139 m_breakpoint_ids.push_back (temp_bp_id); 140 } 141 else 142 { 143 result.AppendErrorWithFormat ("'%s' is not a valid breakpoint ID.\n", string_array[i]); 144 result.SetStatus (eReturnStatusFailed); 145 return; 146 } 147 } 148 } 149 result.SetStatus (eReturnStatusSuccessFinishNoResult); 150 } 151 152 153 // This function takes OLD_ARGS, which is usually the result of breaking the command string arguments into 154 // an array of space-separated strings, and searches through the arguments for any breakpoint ID range specifiers. 155 // Any string in the array that is not part of an ID range specifier is copied directly into NEW_ARGS. If any 156 // ID range specifiers are found, the range is interpreted and a list of canonical breakpoint IDs corresponding to 157 // all the current breakpoints and locations in the range are added to NEW_ARGS. When this function is done, 158 // NEW_ARGS should be a copy of OLD_ARGS, with and ID range specifiers replaced by the members of the range. 159 160 void 161 BreakpointIDList::FindAndReplaceIDRanges (Args &old_args, 162 Target *target, 163 bool allow_locations, 164 CommandReturnObject &result, 165 Args &new_args) 166 { 167 std::string range_start; 168 const char *range_end; 169 const char *current_arg; 170 const size_t num_old_args = old_args.GetArgumentCount(); 171 std::set<std::string> names_found; 172 173 for (size_t i = 0; i < num_old_args; ++i) 174 { 175 bool is_range = false; 176 177 current_arg = old_args.GetArgumentAtIndex (i); 178 if (!allow_locations && strchr(current_arg, '.') != nullptr) 179 { 180 result.AppendErrorWithFormat ("Breakpoint locations not allowed, saw location: %s.", current_arg); 181 new_args.Clear(); 182 return; 183 } 184 185 size_t range_start_len = 0; 186 size_t range_end_pos = 0; 187 Error error; 188 189 if (BreakpointIDList::StringContainsIDRangeExpression (current_arg, &range_start_len, &range_end_pos)) 190 { 191 is_range = true; 192 range_start.assign (current_arg, range_start_len); 193 range_end = current_arg + range_end_pos; 194 } 195 else if (BreakpointID::StringIsBreakpointName(current_arg, error)) 196 { 197 if (!error.Success()) 198 { 199 new_args.Clear(); 200 result.AppendError (error.AsCString()); 201 result.SetStatus (eReturnStatusFailed); 202 return; 203 } 204 else 205 names_found.insert(current_arg); 206 } 207 else if ((i + 2 < num_old_args) 208 && BreakpointID::IsRangeIdentifier (old_args.GetArgumentAtIndex (i+1)) 209 && BreakpointID::IsValidIDExpression (current_arg) 210 && BreakpointID::IsValidIDExpression (old_args.GetArgumentAtIndex (i+2))) 211 { 212 range_start.assign (current_arg); 213 range_end = old_args.GetArgumentAtIndex (i+2); 214 is_range = true; 215 i = i+2; 216 } 217 else 218 { 219 // See if user has specified id.* 220 std::string tmp_str = old_args.GetArgumentAtIndex (i); 221 size_t pos = tmp_str.find ('.'); 222 if (pos != std::string::npos) 223 { 224 std::string bp_id_str = tmp_str.substr (0, pos); 225 if (BreakpointID::IsValidIDExpression (bp_id_str.c_str()) 226 && tmp_str[pos+1] == '*' 227 && tmp_str.length() == (pos + 2)) 228 { 229 break_id_t bp_id; 230 break_id_t bp_loc_id; 231 232 BreakpointID::ParseCanonicalReference (bp_id_str.c_str(), &bp_id, &bp_loc_id); 233 BreakpointSP breakpoint_sp = target->GetBreakpointByID (bp_id); 234 if (! breakpoint_sp) 235 { 236 new_args.Clear(); 237 result.AppendErrorWithFormat ("'%d' is not a valid breakpoint ID.\n", bp_id); 238 result.SetStatus (eReturnStatusFailed); 239 return; 240 } 241 const size_t num_locations = breakpoint_sp->GetNumLocations(); 242 for (size_t j = 0; j < num_locations; ++j) 243 { 244 BreakpointLocation *bp_loc = breakpoint_sp->GetLocationAtIndex(j).get(); 245 StreamString canonical_id_str; 246 BreakpointID::GetCanonicalReference (&canonical_id_str, bp_id, bp_loc->GetID()); 247 new_args.AppendArgument (canonical_id_str.GetData()); 248 } 249 } 250 251 } 252 } 253 254 if (is_range) 255 { 256 break_id_t start_bp_id; 257 break_id_t end_bp_id; 258 break_id_t start_loc_id; 259 break_id_t end_loc_id; 260 261 BreakpointID::ParseCanonicalReference (range_start.c_str(), &start_bp_id, &start_loc_id); 262 BreakpointID::ParseCanonicalReference (range_end, &end_bp_id, &end_loc_id); 263 264 if ((start_bp_id == LLDB_INVALID_BREAK_ID) 265 || (! target->GetBreakpointByID (start_bp_id))) 266 { 267 new_args.Clear(); 268 result.AppendErrorWithFormat ("'%s' is not a valid breakpoint ID.\n", range_start.c_str()); 269 result.SetStatus (eReturnStatusFailed); 270 return; 271 } 272 273 if ((end_bp_id == LLDB_INVALID_BREAK_ID) 274 || (! target->GetBreakpointByID (end_bp_id))) 275 { 276 new_args.Clear(); 277 result.AppendErrorWithFormat ("'%s' is not a valid breakpoint ID.\n", range_end); 278 result.SetStatus (eReturnStatusFailed); 279 return; 280 } 281 282 283 if (((start_loc_id == LLDB_INVALID_BREAK_ID) 284 && (end_loc_id != LLDB_INVALID_BREAK_ID)) 285 || ((start_loc_id != LLDB_INVALID_BREAK_ID) 286 && (end_loc_id == LLDB_INVALID_BREAK_ID))) 287 { 288 new_args.Clear (); 289 result.AppendErrorWithFormat ("Invalid breakpoint id range: Either both ends of range must specify" 290 " a breakpoint location, or neither can specify a breakpoint location.\n"); 291 result.SetStatus (eReturnStatusFailed); 292 return; 293 } 294 295 // We have valid range starting & ending breakpoint IDs. Go through all the breakpoints in the 296 // target and find all the breakpoints that fit into this range, and add them to new_args. 297 298 // Next check to see if we have location id's. If so, make sure the start_bp_id and end_bp_id are 299 // for the same breakpoint; otherwise we have an illegal range: breakpoint id ranges that specify 300 // bp locations are NOT allowed to cross major bp id numbers. 301 302 if ((start_loc_id != LLDB_INVALID_BREAK_ID) 303 || (end_loc_id != LLDB_INVALID_BREAK_ID)) 304 { 305 if (start_bp_id != end_bp_id) 306 { 307 new_args.Clear(); 308 result.AppendErrorWithFormat ("Invalid range: Ranges that specify particular breakpoint locations" 309 " must be within the same major breakpoint; you specified two" 310 " different major breakpoints, %d and %d.\n", 311 start_bp_id, end_bp_id); 312 result.SetStatus (eReturnStatusFailed); 313 return; 314 } 315 } 316 317 const BreakpointList& breakpoints = target->GetBreakpointList(); 318 const size_t num_breakpoints = breakpoints.GetSize(); 319 for (size_t j = 0; j < num_breakpoints; ++j) 320 { 321 Breakpoint *breakpoint = breakpoints.GetBreakpointAtIndex (j).get(); 322 break_id_t cur_bp_id = breakpoint->GetID(); 323 324 if ((cur_bp_id < start_bp_id) || (cur_bp_id > end_bp_id)) 325 continue; 326 327 const size_t num_locations = breakpoint->GetNumLocations(); 328 329 if ((cur_bp_id == start_bp_id) && (start_loc_id != LLDB_INVALID_BREAK_ID)) 330 { 331 for (size_t k = 0; k < num_locations; ++k) 332 { 333 BreakpointLocation * bp_loc = breakpoint->GetLocationAtIndex(k).get(); 334 if ((bp_loc->GetID() >= start_loc_id) && (bp_loc->GetID() <= end_loc_id)) 335 { 336 StreamString canonical_id_str; 337 BreakpointID::GetCanonicalReference (&canonical_id_str, cur_bp_id, bp_loc->GetID()); 338 new_args.AppendArgument (canonical_id_str.GetData()); 339 } 340 } 341 } 342 else if ((cur_bp_id == end_bp_id) && (end_loc_id != LLDB_INVALID_BREAK_ID)) 343 { 344 for (size_t k = 0; k < num_locations; ++k) 345 { 346 BreakpointLocation * bp_loc = breakpoint->GetLocationAtIndex(k).get(); 347 if (bp_loc->GetID() <= end_loc_id) 348 { 349 StreamString canonical_id_str; 350 BreakpointID::GetCanonicalReference (&canonical_id_str, cur_bp_id, bp_loc->GetID()); 351 new_args.AppendArgument (canonical_id_str.GetData()); 352 } 353 } 354 } 355 else 356 { 357 StreamString canonical_id_str; 358 BreakpointID::GetCanonicalReference (&canonical_id_str, cur_bp_id, LLDB_INVALID_BREAK_ID); 359 new_args.AppendArgument (canonical_id_str.GetData()); 360 } 361 } 362 } 363 else // else is_range was false 364 { 365 new_args.AppendArgument (current_arg); 366 } 367 } 368 369 // Okay, now see if we found any names, and if we did, add them: 370 if (target && names_found.size()) 371 { 372 for (BreakpointSP bkpt_sp : target->GetBreakpointList().Breakpoints()) 373 { 374 for (std::string name : names_found) 375 { 376 if (bkpt_sp->MatchesName(name.c_str())) 377 { 378 StreamString canonical_id_str; 379 BreakpointID::GetCanonicalReference (&canonical_id_str, bkpt_sp->GetID(), LLDB_INVALID_BREAK_ID); 380 new_args.AppendArgument (canonical_id_str.GetData()); 381 } 382 } 383 } 384 } 385 386 result.SetStatus (eReturnStatusSuccessFinishNoResult); 387 } 388 389 bool 390 BreakpointIDList::StringContainsIDRangeExpression (const char *in_string, 391 size_t *range_start_len, 392 size_t *range_end_pos) 393 { 394 bool is_range_expression = false; 395 std::string arg_str = in_string; 396 std::string::size_type idx; 397 std::string::size_type start_pos = 0; 398 399 *range_start_len = 0; 400 *range_end_pos = 0; 401 402 int specifiers_size = 0; 403 for (int i = 0; BreakpointID::g_range_specifiers[i] != nullptr; ++i) 404 ++specifiers_size; 405 406 for (int i = 0; i < specifiers_size && !is_range_expression; ++i) 407 { 408 const char *specifier_str = BreakpointID::g_range_specifiers[i]; 409 size_t len = strlen (specifier_str); 410 idx = arg_str.find (BreakpointID::g_range_specifiers[i]); 411 if (idx != std::string::npos) 412 { 413 *range_start_len = idx - start_pos; 414 std::string start_str = arg_str.substr (start_pos, *range_start_len); 415 if (idx + len < arg_str.length()) 416 { 417 *range_end_pos = idx + len; 418 std::string end_str = arg_str.substr (*range_end_pos); 419 if (BreakpointID::IsValidIDExpression (start_str.c_str()) 420 && BreakpointID::IsValidIDExpression (end_str.c_str())) 421 { 422 is_range_expression = true; 423 //*range_start = start_str; 424 //*range_end = end_str; 425 } 426 } 427 } 428 } 429 430 if (!is_range_expression) 431 { 432 *range_start_len = 0; 433 *range_end_pos = 0; 434 } 435 436 return is_range_expression; 437 } 438