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