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 (uint32_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 (uint32_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, uint32_t *position) 93 { 94 BreakpointIDArray::iterator tmp_pos; 95 96 for (size_t i = 0; i < m_breakpoint_ids.size(); ++i) 97 { 98 BreakpointID tmp_id = m_breakpoint_ids[i]; 99 if (tmp_id.GetBreakpointID() == bp_id.GetBreakpointID() 100 && tmp_id.GetLocationID() == bp_id.GetLocationID()) 101 { 102 *position = i; 103 return true; 104 } 105 } 106 107 return false; 108 } 109 110 bool 111 BreakpointIDList::FindBreakpointID (const char *bp_id_str, uint32_t *position) 112 { 113 BreakpointID temp_bp_id; 114 break_id_t bp_id; 115 break_id_t loc_id; 116 117 if (BreakpointID::ParseCanonicalReference (bp_id_str, &bp_id, &loc_id)) 118 { 119 temp_bp_id.SetID (bp_id, loc_id); 120 return FindBreakpointID (temp_bp_id, position); 121 } 122 else 123 return false; 124 } 125 126 void 127 BreakpointIDList::InsertStringArray (const char **string_array, uint32_t array_size, CommandReturnObject &result) 128 { 129 if (string_array == NULL) 130 return; 131 132 for (uint32_t i = 0; i < array_size; ++i) 133 { 134 break_id_t bp_id; 135 break_id_t loc_id; 136 137 if (BreakpointID::ParseCanonicalReference (string_array[i], &bp_id, &loc_id)) 138 { 139 if (bp_id != LLDB_INVALID_BREAK_ID) 140 { 141 BreakpointID temp_bp_id(bp_id, loc_id); 142 m_breakpoint_ids.push_back (temp_bp_id); 143 } 144 else 145 { 146 result.AppendErrorWithFormat ("'%s' is not a valid breakpoint ID.\n", string_array[i]); 147 result.SetStatus (eReturnStatusFailed); 148 return; 149 } 150 } 151 } 152 result.SetStatus (eReturnStatusSuccessFinishNoResult); 153 } 154 155 156 // This function takes OLD_ARGS, which is usually the result of breaking the command string arguments into 157 // an array of space-separated strings, and searches through the arguments for any breakpoint ID range specifiers. 158 // Any string in the array that is not part of an ID range specifier is copied directly into NEW_ARGS. If any 159 // ID range specifiers are found, the range is interpreted and a list of canonical breakpoint IDs corresponding to 160 // all the current breakpoints and locations in the range are added to NEW_ARGS. When this function is done, 161 // NEW_ARGS should be a copy of OLD_ARGS, with and ID range specifiers replaced by the members of the range. 162 163 void 164 BreakpointIDList::FindAndReplaceIDRanges (Args &old_args, Target *target, 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 172 for (size_t i = 0; i < num_old_args; ++i) 173 { 174 bool is_range = false; 175 current_arg = old_args.GetArgumentAtIndex (i); 176 177 uint32_t range_start_len = 0; 178 uint32_t range_end_pos = 0; 179 if (BreakpointIDList::StringContainsIDRangeExpression (current_arg, &range_start_len, &range_end_pos)) 180 { 181 is_range = true; 182 range_start.assign (current_arg, range_start_len); 183 range_end = current_arg + range_end_pos; 184 } 185 else if ((i + 2 < num_old_args) 186 && BreakpointID::IsRangeIdentifier (old_args.GetArgumentAtIndex (i+1)) 187 && BreakpointID::IsValidIDExpression (current_arg) 188 && BreakpointID::IsValidIDExpression (old_args.GetArgumentAtIndex (i+2))) 189 { 190 range_start.assign (current_arg); 191 range_end = old_args.GetArgumentAtIndex (i+2); 192 is_range = true; 193 i = i+2; 194 } 195 else 196 { 197 // See if user has specified id.* 198 std::string tmp_str = old_args.GetArgumentAtIndex (i); 199 size_t pos = tmp_str.find ('.'); 200 if (pos != std::string::npos) 201 { 202 std::string bp_id_str = tmp_str.substr (0, pos); 203 if (BreakpointID::IsValidIDExpression (bp_id_str.c_str()) 204 && tmp_str[pos+1] == '*' 205 && tmp_str.length() == (pos + 2)) 206 { 207 break_id_t bp_id; 208 break_id_t bp_loc_id; 209 210 BreakpointID::ParseCanonicalReference (bp_id_str.c_str(), &bp_id, &bp_loc_id); 211 BreakpointSP breakpoint_sp = target->GetBreakpointByID (bp_id); 212 if (! breakpoint_sp) 213 { 214 new_args.Clear(); 215 result.AppendErrorWithFormat ("'%d' is not a valid breakpoint ID.\n", bp_id); 216 result.SetStatus (eReturnStatusFailed); 217 return; 218 } 219 const size_t num_locations = breakpoint_sp->GetNumLocations(); 220 for (size_t j = 0; j < num_locations; ++j) 221 { 222 BreakpointLocation *bp_loc = breakpoint_sp->GetLocationAtIndex(j).get(); 223 StreamString canonical_id_str; 224 BreakpointID::GetCanonicalReference (&canonical_id_str, bp_id, bp_loc->GetID()); 225 new_args.AppendArgument (canonical_id_str.GetData()); 226 } 227 } 228 229 } 230 } 231 232 if (is_range) 233 { 234 break_id_t start_bp_id; 235 break_id_t end_bp_id; 236 break_id_t start_loc_id; 237 break_id_t end_loc_id; 238 239 BreakpointID::ParseCanonicalReference (range_start.c_str(), &start_bp_id, &start_loc_id); 240 BreakpointID::ParseCanonicalReference (range_end, &end_bp_id, &end_loc_id); 241 242 if ((start_bp_id == LLDB_INVALID_BREAK_ID) 243 || (! target->GetBreakpointByID (start_bp_id))) 244 { 245 new_args.Clear(); 246 result.AppendErrorWithFormat ("'%s' is not a valid breakpoint ID.\n", range_start.c_str()); 247 result.SetStatus (eReturnStatusFailed); 248 return; 249 } 250 251 if ((end_bp_id == LLDB_INVALID_BREAK_ID) 252 || (! target->GetBreakpointByID (end_bp_id))) 253 { 254 new_args.Clear(); 255 result.AppendErrorWithFormat ("'%s' is not a valid breakpoint ID.\n", range_end); 256 result.SetStatus (eReturnStatusFailed); 257 return; 258 } 259 260 261 if (((start_loc_id == LLDB_INVALID_BREAK_ID) 262 && (end_loc_id != LLDB_INVALID_BREAK_ID)) 263 || ((start_loc_id != LLDB_INVALID_BREAK_ID) 264 && (end_loc_id == LLDB_INVALID_BREAK_ID))) 265 { 266 new_args.Clear (); 267 result.AppendErrorWithFormat ("Invalid breakpoint id range: Either both ends of range must specify" 268 " a breakpoint location, or neither can specify a breakpoint location.\n"); 269 result.SetStatus (eReturnStatusFailed); 270 return; 271 } 272 273 // We have valid range starting & ending breakpoint IDs. Go through all the breakpoints in the 274 // target and find all the breakpoints that fit into this range, and add them to new_args. 275 276 // Next check to see if we have location id's. If so, make sure the start_bp_id and end_bp_id are 277 // for the same breakpoint; otherwise we have an illegal range: breakpoint id ranges that specify 278 // bp locations are NOT allowed to cross major bp id numbers. 279 280 if ((start_loc_id != LLDB_INVALID_BREAK_ID) 281 || (end_loc_id != LLDB_INVALID_BREAK_ID)) 282 { 283 if (start_bp_id != end_bp_id) 284 { 285 new_args.Clear(); 286 result.AppendErrorWithFormat ("Invalid range: Ranges that specify particular breakpoint locations" 287 " must be within the same major breakpoint; you specified two" 288 " different major breakpoints, %d and %d.\n", 289 start_bp_id, end_bp_id); 290 result.SetStatus (eReturnStatusFailed); 291 return; 292 } 293 } 294 295 const BreakpointList& breakpoints = target->GetBreakpointList(); 296 const size_t num_breakpoints = breakpoints.GetSize(); 297 for (size_t j = 0; j < num_breakpoints; ++j) 298 { 299 Breakpoint *breakpoint = breakpoints.GetBreakpointAtIndex (j).get(); 300 break_id_t cur_bp_id = breakpoint->GetID(); 301 302 if ((cur_bp_id < start_bp_id) || (cur_bp_id > end_bp_id)) 303 continue; 304 305 const size_t num_locations = breakpoint->GetNumLocations(); 306 307 if ((cur_bp_id == start_bp_id) && (start_loc_id != LLDB_INVALID_BREAK_ID)) 308 { 309 for (size_t k = 0; k < num_locations; ++k) 310 { 311 BreakpointLocation * bp_loc = breakpoint->GetLocationAtIndex(k).get(); 312 if ((bp_loc->GetID() >= start_loc_id) && (bp_loc->GetID() <= end_loc_id)) 313 { 314 StreamString canonical_id_str; 315 BreakpointID::GetCanonicalReference (&canonical_id_str, cur_bp_id, bp_loc->GetID()); 316 new_args.AppendArgument (canonical_id_str.GetData()); 317 } 318 } 319 } 320 else if ((cur_bp_id == end_bp_id) && (end_loc_id != LLDB_INVALID_BREAK_ID)) 321 { 322 for (size_t k = 0; k < num_locations; ++k) 323 { 324 BreakpointLocation * bp_loc = breakpoint->GetLocationAtIndex(k).get(); 325 if (bp_loc->GetID() <= end_loc_id) 326 { 327 StreamString canonical_id_str; 328 BreakpointID::GetCanonicalReference (&canonical_id_str, cur_bp_id, bp_loc->GetID()); 329 new_args.AppendArgument (canonical_id_str.GetData()); 330 } 331 } 332 } 333 else 334 { 335 StreamString canonical_id_str; 336 BreakpointID::GetCanonicalReference (&canonical_id_str, cur_bp_id, LLDB_INVALID_BREAK_ID); 337 new_args.AppendArgument (canonical_id_str.GetData()); 338 } 339 } 340 } 341 else // else is_range was false 342 { 343 new_args.AppendArgument (current_arg); 344 } 345 } 346 347 result.SetStatus (eReturnStatusSuccessFinishNoResult); 348 return; 349 } 350 351 bool 352 BreakpointIDList::StringContainsIDRangeExpression (const char *in_string, 353 uint32_t *range_start_len, 354 uint32_t *range_end_pos) 355 { 356 bool is_range_expression = false; 357 std::string arg_str = in_string; 358 std::string::size_type idx; 359 std::string::size_type start_pos = 0; 360 361 *range_start_len = 0; 362 *range_end_pos = 0; 363 364 int specifiers_size = 0; 365 for (int i = 0; BreakpointID::g_range_specifiers[i] != NULL; ++i) 366 ++specifiers_size; 367 368 for (int i = 0; i < specifiers_size && !is_range_expression; ++i) 369 { 370 const char *specifier_str = BreakpointID::g_range_specifiers[i]; 371 int len = strlen (specifier_str); 372 idx = arg_str.find (BreakpointID::g_range_specifiers[i]); 373 if (idx != std::string::npos) 374 { 375 *range_start_len = idx - start_pos; 376 std::string start_str = arg_str.substr (start_pos, *range_start_len); 377 if (idx + len < arg_str.length()) 378 { 379 *range_end_pos = idx + len; 380 std::string end_str = arg_str.substr (*range_end_pos); 381 if (BreakpointID::IsValidIDExpression (start_str.c_str()) 382 && BreakpointID::IsValidIDExpression (end_str.c_str())) 383 { 384 is_range_expression = true; 385 //*range_start = start_str; 386 //*range_end = end_str; 387 } 388 } 389 } 390 } 391 392 if (!is_range_expression) 393 { 394 *range_start_len = 0; 395 *range_end_pos = 0; 396 } 397 398 return is_range_expression; 399 } 400