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