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