1 //===-- StackFrame.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/Target/StackFrame.h" 11 12 // C Includes 13 // C++ Includes 14 // Other libraries and framework includes 15 // Project includes 16 #include "lldb/Core/Module.h" 17 #include "lldb/Core/Disassembler.h" 18 #include "lldb/Core/Value.h" 19 #include "lldb/Core/ValueObjectVariable.h" 20 #include "lldb/Symbol/Function.h" 21 #include "lldb/Symbol/VariableList.h" 22 #include "lldb/Target/ExecutionContext.h" 23 #include "lldb/Target/Process.h" 24 #include "lldb/Target/RegisterContext.h" 25 #include "lldb/Target/Target.h" 26 #include "lldb/Target/Thread.h" 27 28 using namespace lldb; 29 using namespace lldb_private; 30 31 // The first bits in the flags are reserved for the SymbolContext::Scope bits 32 // so we know if we have tried to look up information in our internal symbol 33 // context (m_sc) already. 34 #define RESOLVED_FRAME_CODE_ADDR (uint32_t(eSymbolContextEverything + 1)) 35 #define RESOLVED_FRAME_ID_START_ADDR (RESOLVED_FRAME_CODE_ADDR << 1) 36 #define RESOLVED_FRAME_ID_SYMBOL_SCOPE (RESOLVED_FRAME_ID_START_ADDR << 1) 37 #define GOT_FRAME_BASE (RESOLVED_FRAME_ID_SYMBOL_SCOPE << 1) 38 #define RESOLVED_VARIABLES (GOT_FRAME_BASE << 1) 39 40 StackFrame::StackFrame 41 ( 42 lldb::user_id_t frame_idx, 43 lldb::user_id_t unwind_frame_index, 44 Thread &thread, 45 lldb::addr_t cfa, 46 lldb::addr_t pc, 47 const SymbolContext *sc_ptr 48 ) : 49 m_frame_index (frame_idx), 50 m_unwind_frame_index (unwind_frame_index), 51 m_thread (thread), 52 m_reg_context_sp (), 53 m_id (LLDB_INVALID_ADDRESS, cfa, NULL), 54 m_frame_code_addr (NULL, pc), 55 m_sc (), 56 m_flags (), 57 m_frame_base (), 58 m_frame_base_error (), 59 m_variable_list_sp (), 60 m_variable_list_value_objects () 61 { 62 if (sc_ptr != NULL) 63 { 64 m_sc = *sc_ptr; 65 m_flags.Set(m_sc.GetResolvedMask ()); 66 } 67 } 68 69 StackFrame::StackFrame 70 ( 71 lldb::user_id_t frame_idx, 72 lldb::user_id_t unwind_frame_index, 73 Thread &thread, 74 const RegisterContextSP ®_context_sp, 75 lldb::addr_t cfa, 76 lldb::addr_t pc, 77 const SymbolContext *sc_ptr 78 ) : 79 m_frame_index (frame_idx), 80 m_unwind_frame_index (unwind_frame_index), 81 m_thread (thread), 82 m_reg_context_sp (reg_context_sp), 83 m_id (LLDB_INVALID_ADDRESS, cfa, NULL), 84 m_frame_code_addr (NULL, pc), 85 m_sc (), 86 m_flags (), 87 m_frame_base (), 88 m_frame_base_error (), 89 m_variable_list_sp (), 90 m_variable_list_value_objects () 91 { 92 if (sc_ptr != NULL) 93 { 94 m_sc = *sc_ptr; 95 m_flags.Set(m_sc.GetResolvedMask ()); 96 } 97 98 if (reg_context_sp && !m_sc.target_sp) 99 { 100 m_sc.target_sp = reg_context_sp->GetThread().GetProcess().GetTarget().GetSP(); 101 m_flags.Set (eSymbolContextTarget); 102 } 103 } 104 105 StackFrame::StackFrame 106 ( 107 lldb::user_id_t frame_idx, 108 lldb::user_id_t unwind_frame_index, 109 Thread &thread, 110 const RegisterContextSP ®_context_sp, 111 lldb::addr_t cfa, 112 const Address& pc_addr, 113 const SymbolContext *sc_ptr 114 ) : 115 m_frame_index (frame_idx), 116 m_unwind_frame_index (unwind_frame_index), 117 m_thread (thread), 118 m_reg_context_sp (reg_context_sp), 119 m_id (LLDB_INVALID_ADDRESS, cfa, NULL), 120 m_frame_code_addr (pc_addr), 121 m_sc (), 122 m_flags (), 123 m_frame_base (), 124 m_frame_base_error (), 125 m_variable_list_sp (), 126 m_variable_list_value_objects () 127 { 128 if (sc_ptr != NULL) 129 { 130 m_sc = *sc_ptr; 131 m_flags.Set(m_sc.GetResolvedMask ()); 132 } 133 134 if (m_sc.target_sp.get() == NULL && reg_context_sp) 135 { 136 m_sc.target_sp = reg_context_sp->GetThread().GetProcess().GetTarget().GetSP(); 137 m_flags.Set (eSymbolContextTarget); 138 } 139 140 if (m_sc.module_sp.get() == NULL && pc_addr.GetSection()) 141 { 142 Module *pc_module = pc_addr.GetSection()->GetModule(); 143 if (pc_module) 144 { 145 m_sc.module_sp = pc_module->GetSP(); 146 m_flags.Set (eSymbolContextModule); 147 } 148 } 149 } 150 151 152 //---------------------------------------------------------------------- 153 // Destructor 154 //---------------------------------------------------------------------- 155 StackFrame::~StackFrame() 156 { 157 } 158 159 StackID& 160 StackFrame::GetStackID() 161 { 162 // Make sure we have resolved our stack ID's start PC before we give 163 // it out to any external clients. This allows us to not have to lookup 164 // this information if it is never asked for. 165 if (m_flags.IsClear(RESOLVED_FRAME_ID_START_ADDR)) 166 { 167 m_flags.Set (RESOLVED_FRAME_ID_START_ADDR); 168 169 if (m_id.GetStartAddress() == LLDB_INVALID_ADDRESS) 170 { 171 // Resolve our PC to section offset if we haven't alreday done so 172 // and if we don't have a module. The resolved address section will 173 // contain the module to which it belongs. 174 if (!m_sc.module_sp && m_flags.IsClear(RESOLVED_FRAME_CODE_ADDR)) 175 GetFrameCodeAddress(); 176 177 if (GetSymbolContext (eSymbolContextFunction).function) 178 { 179 m_id.SetStartAddress (m_sc.function->GetAddressRange().GetBaseAddress().GetLoadAddress (&m_thread.GetProcess())); 180 } 181 else if (GetSymbolContext (eSymbolContextSymbol).symbol) 182 { 183 AddressRange *symbol_range_ptr = m_sc.symbol->GetAddressRangePtr(); 184 if (symbol_range_ptr) 185 m_id.SetStartAddress(symbol_range_ptr->GetBaseAddress().GetLoadAddress (&m_thread.GetProcess())); 186 } 187 188 // We didn't find a function or symbol, just use the frame code address 189 // which will be the same as the PC in the frame. 190 if (m_id.GetStartAddress() == LLDB_INVALID_ADDRESS) 191 m_id.SetStartAddress (m_frame_code_addr.GetLoadAddress (&m_thread.GetProcess())); 192 } 193 } 194 195 if (m_flags.IsClear (RESOLVED_FRAME_ID_SYMBOL_SCOPE)) 196 { 197 if (m_id.GetSymbolContextScope ()) 198 { 199 m_flags.Set (RESOLVED_FRAME_ID_SYMBOL_SCOPE); 200 } 201 else 202 { 203 GetSymbolContext (eSymbolContextFunction | eSymbolContextBlock); 204 205 if (m_sc.block) 206 { 207 Block *inline_block = m_sc.block->GetContainingInlinedBlock(); 208 if (inline_block) 209 { 210 // Use the block with the inlined function info 211 // as the symbol context since we want this frame 212 // to have only the variables for the inlined function 213 SetSymbolContextScope (inline_block); 214 } 215 else 216 { 217 // This block is not inlined with means it has no 218 // inlined parents either, so we want to use the top 219 // most function block. 220 SetSymbolContextScope (&m_sc.function->GetBlock(false)); 221 } 222 } 223 else 224 { 225 // The current stack frame doesn't have a block. Check to see 226 // if it has a symbol. If it does we will use this as the 227 // symbol scope. It is ok if "m_sc.symbol" is NULL below as 228 // it will set the symbol context to NULL and set the 229 // RESOLVED_FRAME_ID_SYMBOL_SCOPE flag bit. 230 GetSymbolContext (eSymbolContextSymbol); 231 SetSymbolContextScope (m_sc.symbol); 232 } 233 } 234 } 235 return m_id; 236 } 237 238 void 239 StackFrame::SetSymbolContextScope (SymbolContextScope *symbol_scope) 240 { 241 m_flags.Set (RESOLVED_FRAME_ID_SYMBOL_SCOPE); 242 m_id.SetSymbolContextScope (symbol_scope); 243 } 244 245 Address& 246 StackFrame::GetFrameCodeAddress() 247 { 248 if (m_flags.IsClear(RESOLVED_FRAME_CODE_ADDR) && !m_frame_code_addr.IsSectionOffset()) 249 { 250 m_flags.Set (RESOLVED_FRAME_CODE_ADDR); 251 252 // Resolve the PC into a temporary address because if ResolveLoadAddress 253 // fails to resolve the address, it will clear the address object... 254 Address resolved_pc; 255 if (m_thread.GetProcess().ResolveLoadAddress(m_frame_code_addr.GetOffset(), resolved_pc)) 256 { 257 m_frame_code_addr = resolved_pc; 258 const Section *section = m_frame_code_addr.GetSection(); 259 if (section) 260 { 261 Module *module = section->GetModule(); 262 if (module) 263 { 264 m_sc.module_sp = module->GetSP(); 265 if (m_sc.module_sp) 266 m_flags.Set(eSymbolContextModule); 267 } 268 } 269 } 270 } 271 return m_frame_code_addr; 272 } 273 274 void 275 StackFrame::ChangePC (addr_t pc) 276 { 277 m_frame_code_addr.SetOffset(pc); 278 m_frame_code_addr.SetSection(NULL); 279 m_sc.Clear(); 280 m_flags.SetAllFlagBits(0); 281 m_thread.ClearStackFrames (); 282 } 283 284 const char * 285 StackFrame::Disassemble () 286 { 287 if (m_disassembly.GetSize() == 0) 288 { 289 ExecutionContext exe_ctx; 290 Calculate(exe_ctx); 291 Target &target = m_thread.GetProcess().GetTarget(); 292 Disassembler::Disassemble (target.GetDebugger(), 293 target.GetArchitecture(), 294 exe_ctx, 295 0, 296 false, 297 m_disassembly); 298 if (m_disassembly.GetSize() == 0) 299 return NULL; 300 } 301 return m_disassembly.GetData(); 302 } 303 304 //---------------------------------------------------------------------- 305 // Get the symbol context if we already haven't done so by resolving the 306 // PC address as much as possible. This way when we pass around a 307 // StackFrame object, everyone will have as much information as 308 // possible and no one will ever have to look things up manually. 309 //---------------------------------------------------------------------- 310 const SymbolContext& 311 StackFrame::GetSymbolContext (uint32_t resolve_scope) 312 { 313 // Copy our internal symbol context into "sc". 314 if ((m_flags.GetAllFlagBits() & resolve_scope) != resolve_scope) 315 { 316 // Resolve our PC to section offset if we haven't alreday done so 317 // and if we don't have a module. The resolved address section will 318 // contain the module to which it belongs 319 if (!m_sc.module_sp && m_flags.IsClear(RESOLVED_FRAME_CODE_ADDR)) 320 GetFrameCodeAddress(); 321 322 // If this is not frame zero, then we need to subtract 1 from the PC 323 // value when doing address lookups since the PC will be on the 324 // instruction following the function call instruction... 325 326 Address lookup_addr(GetFrameCodeAddress()); 327 if (m_frame_index > 0 && lookup_addr.IsValid()) 328 { 329 addr_t offset = lookup_addr.GetOffset(); 330 if (offset > 0) 331 lookup_addr.SetOffset(offset - 1); 332 } 333 334 335 uint32_t resolved = 0; 336 if (m_sc.module_sp) 337 { 338 // We have something in our stack frame symbol context, lets check 339 // if we haven't already tried to lookup one of those things. If we 340 // haven't then we will do the query. 341 342 uint32_t actual_resolve_scope = 0; 343 344 if (resolve_scope & eSymbolContextCompUnit) 345 { 346 if (m_flags.IsClear (eSymbolContextCompUnit)) 347 { 348 if (m_sc.comp_unit) 349 resolved |= eSymbolContextCompUnit; 350 else 351 actual_resolve_scope |= eSymbolContextCompUnit; 352 } 353 } 354 355 if (resolve_scope & eSymbolContextFunction) 356 { 357 if (m_flags.IsClear (eSymbolContextFunction)) 358 { 359 if (m_sc.function) 360 resolved |= eSymbolContextFunction; 361 else 362 actual_resolve_scope |= eSymbolContextFunction; 363 } 364 } 365 366 if (resolve_scope & eSymbolContextBlock) 367 { 368 if (m_flags.IsClear (eSymbolContextBlock)) 369 { 370 if (m_sc.block) 371 resolved |= eSymbolContextBlock; 372 else 373 actual_resolve_scope |= eSymbolContextBlock; 374 } 375 } 376 377 if (resolve_scope & eSymbolContextSymbol) 378 { 379 if (m_flags.IsClear (eSymbolContextSymbol)) 380 { 381 if (m_sc.symbol) 382 resolved |= eSymbolContextSymbol; 383 else 384 actual_resolve_scope |= eSymbolContextSymbol; 385 } 386 } 387 388 if (resolve_scope & eSymbolContextLineEntry) 389 { 390 if (m_flags.IsClear (eSymbolContextLineEntry)) 391 { 392 if (m_sc.line_entry.IsValid()) 393 resolved |= eSymbolContextLineEntry; 394 else 395 actual_resolve_scope |= eSymbolContextLineEntry; 396 } 397 } 398 399 if (actual_resolve_scope) 400 { 401 // We might be resolving less information than what is already 402 // in our current symbol context so resolve into a temporary 403 // symbol context "sc" so we don't clear out data we have 404 // already found in "m_sc" 405 SymbolContext sc; 406 // Set flags that indicate what we have tried to resolve 407 resolved |= m_sc.module_sp->ResolveSymbolContextForAddress (lookup_addr, actual_resolve_scope, sc); 408 // Only replace what we didn't already have as we may have 409 // information for an inlined function scope that won't match 410 // what a standard lookup by address would match 411 if ((resolved & eSymbolContextCompUnit) && m_sc.comp_unit == NULL) 412 m_sc.comp_unit = sc.comp_unit; 413 if ((resolved & eSymbolContextFunction) && m_sc.function == NULL) 414 m_sc.function = sc.function; 415 if ((resolved & eSymbolContextBlock) && m_sc.block == NULL) 416 m_sc.block = sc.block; 417 if ((resolved & eSymbolContextSymbol) && m_sc.symbol == NULL) 418 m_sc.symbol = sc.symbol; 419 if ((resolved & eSymbolContextLineEntry) && !m_sc.line_entry.IsValid()) 420 m_sc.line_entry = sc.line_entry; 421 422 } 423 } 424 else 425 { 426 // If we don't have a module, then we can't have the compile unit, 427 // function, block, line entry or symbol, so we can safely call 428 // ResolveSymbolContextForAddress with our symbol context member m_sc. 429 resolved |= m_thread.GetProcess().GetTarget().GetImages().ResolveSymbolContextForAddress (lookup_addr, resolve_scope, m_sc); 430 } 431 432 // If the target was requested add that: 433 if (m_sc.target_sp.get() == NULL) 434 { 435 m_sc.target_sp = CalculateProcess()->GetTarget().GetSP(); 436 if (m_sc.target_sp) 437 resolved |= eSymbolContextTarget; 438 } 439 440 // Update our internal flags so we remember what we have tried to locate so 441 // we don't have to keep trying when more calls to this function are made. 442 // We might have dug up more information that was requested (for example 443 // if we were asked to only get the block, we will have gotten the 444 // compile unit, and function) so set any additional bits that we resolved 445 m_flags.Set (resolve_scope | resolved); 446 } 447 448 // Return the symbol context with everything that was possible to resolve 449 // resolved. 450 return m_sc; 451 } 452 453 454 VariableList * 455 StackFrame::GetVariableList (bool get_file_globals) 456 { 457 if (m_flags.IsClear(RESOLVED_VARIABLES)) 458 { 459 m_flags.Set(RESOLVED_VARIABLES); 460 461 GetSymbolContext (eSymbolContextCompUnit | 462 eSymbolContextFunction | 463 eSymbolContextBlock); 464 465 if (m_sc.block) 466 { 467 bool get_child_variables = true; 468 bool can_create = true; 469 m_variable_list_sp = m_sc.function->GetBlock (can_create).GetVariableList (get_child_variables, can_create); 470 } 471 472 if (get_file_globals && m_sc.comp_unit) 473 { 474 VariableListSP global_variable_list_sp (m_sc.comp_unit->GetVariableList(true)); 475 if (m_variable_list_sp) 476 m_variable_list_sp->AddVariables (global_variable_list_sp.get()); 477 else 478 m_variable_list_sp = global_variable_list_sp; 479 } 480 } 481 return m_variable_list_sp.get(); 482 } 483 484 485 bool 486 StackFrame::GetFrameBaseValue (Scalar &frame_base, Error *error_ptr) 487 { 488 if (m_flags.IsClear(GOT_FRAME_BASE)) 489 { 490 if (m_sc.function) 491 { 492 m_frame_base.Clear(); 493 m_frame_base_error.Clear(); 494 495 m_flags.Set(GOT_FRAME_BASE); 496 ExecutionContext exe_ctx (&m_thread.GetProcess(), &m_thread, this); 497 Value expr_value; 498 if (m_sc.function->GetFrameBaseExpression().Evaluate(&exe_ctx, NULL, NULL, expr_value, &m_frame_base_error) < 0) 499 { 500 // We should really have an error if evaluate returns, but in case 501 // we don't, lets set the error to something at least. 502 if (m_frame_base_error.Success()) 503 m_frame_base_error.SetErrorString("Evaluation of the frame base expression failed."); 504 } 505 else 506 { 507 m_frame_base = expr_value.ResolveValue(&exe_ctx, NULL); 508 } 509 } 510 else 511 { 512 m_frame_base_error.SetErrorString ("No function in symbol context."); 513 } 514 } 515 516 if (m_frame_base_error.Success()) 517 frame_base = m_frame_base; 518 519 if (error_ptr) 520 *error_ptr = m_frame_base_error; 521 return m_frame_base_error.Success(); 522 } 523 524 RegisterContext * 525 StackFrame::GetRegisterContext () 526 { 527 if (m_reg_context_sp.get() == NULL) 528 m_reg_context_sp.reset (m_thread.CreateRegisterContextForFrame (this)); 529 return m_reg_context_sp.get(); 530 } 531 532 bool 533 StackFrame::HasDebugInformation () 534 { 535 GetSymbolContext (eSymbolContextLineEntry); 536 return m_sc.line_entry.IsValid(); 537 } 538 539 540 ValueObjectSP 541 StackFrame::GetValueObjectForFrameVariable (const VariableSP &variable_sp) 542 { 543 ValueObjectSP valobj_sp; 544 VariableList *var_list = GetVariableList (true); 545 if (var_list) 546 { 547 // Make sure the variable is a frame variable 548 const uint32_t var_idx = var_list->FindIndexForVariable (variable_sp.get()); 549 const uint32_t num_variables = var_list->GetSize(); 550 if (var_idx < num_variables) 551 { 552 valobj_sp = m_variable_list_value_objects.GetValueObjectAtIndex (var_idx); 553 if (valobj_sp.get() == NULL) 554 { 555 if (m_variable_list_value_objects.GetSize() < num_variables) 556 m_variable_list_value_objects.Resize(num_variables); 557 valobj_sp.reset (new ValueObjectVariable (variable_sp)); 558 m_variable_list_value_objects.SetValueObjectAtIndex (var_idx, valobj_sp); 559 } 560 } 561 } 562 return valobj_sp; 563 } 564 565 ValueObjectSP 566 StackFrame::TrackGlobalVariable (const VariableSP &variable_sp) 567 { 568 // Check to make sure we aren't already tracking this variable? 569 ValueObjectSP valobj_sp (GetValueObjectForFrameVariable (variable_sp)); 570 if (!valobj_sp) 571 { 572 // We aren't already tracking this global 573 VariableList *var_list = GetVariableList (true); 574 // If this frame has no variables, create a new list 575 if (var_list == NULL) 576 m_variable_list_sp.reset (new VariableList()); 577 578 // Add the global/static variable to this frame 579 m_variable_list_sp->AddVariable (variable_sp); 580 581 // Now make a value object for it so we can track its changes 582 valobj_sp = GetValueObjectForFrameVariable (variable_sp); 583 } 584 return valobj_sp; 585 } 586 587 bool 588 StackFrame::IsInlined () 589 { 590 if (m_sc.block == NULL) 591 GetSymbolContext (eSymbolContextBlock); 592 if (m_sc.block) 593 return m_sc.block->GetContainingInlinedBlock() != NULL; 594 return false; 595 } 596 597 Target * 598 StackFrame::CalculateTarget () 599 { 600 return m_thread.CalculateTarget(); 601 } 602 603 Process * 604 StackFrame::CalculateProcess () 605 { 606 return m_thread.CalculateProcess(); 607 } 608 609 Thread * 610 StackFrame::CalculateThread () 611 { 612 return &m_thread; 613 } 614 615 StackFrame * 616 StackFrame::CalculateStackFrame () 617 { 618 return this; 619 } 620 621 622 void 623 StackFrame::Calculate (ExecutionContext &exe_ctx) 624 { 625 m_thread.Calculate (exe_ctx); 626 exe_ctx.frame = this; 627 } 628 629 void 630 StackFrame::Dump (Stream *strm, bool show_frame_index) 631 { 632 if (strm == NULL) 633 return; 634 635 if (show_frame_index) 636 strm->Printf("frame #%u: ", m_frame_index); 637 strm->Printf("0x%0*llx", m_thread.GetProcess().GetAddressByteSize() * 2, GetFrameCodeAddress().GetLoadAddress(&m_thread.GetProcess())); 638 GetSymbolContext(eSymbolContextEverything); 639 strm->PutCString(", where = "); 640 // TODO: need to get the 641 const bool show_module = true; 642 const bool show_inline = true; 643 m_sc.DumpStopContext(strm, &m_thread.GetProcess(), GetFrameCodeAddress(), show_module, show_inline); 644 } 645 646 void 647 StackFrame::UpdateCurrentFrameFromPreviousFrame (StackFrame &prev_frame) 648 { 649 assert (GetStackID() == prev_frame.GetStackID()); // TODO: remove this after some testing 650 m_variable_list_sp = prev_frame.m_variable_list_sp; 651 m_variable_list_value_objects.Swap (prev_frame.m_variable_list_value_objects); 652 if (!m_disassembly.GetString().empty()) 653 m_disassembly.GetString().swap (m_disassembly.GetString()); 654 } 655 656 657 void 658 StackFrame::UpdatePreviousFrameFromCurrentFrame (StackFrame &curr_frame) 659 { 660 assert (GetStackID() == curr_frame.GetStackID()); // TODO: remove this after some testing 661 assert (&m_thread == &curr_frame.m_thread); 662 m_frame_index = curr_frame.m_frame_index; 663 m_unwind_frame_index = curr_frame.m_unwind_frame_index; 664 m_reg_context_sp = curr_frame.m_reg_context_sp; 665 m_frame_code_addr = curr_frame.m_frame_code_addr; 666 assert (m_sc.target_sp.get() == NULL || curr_frame.m_sc.target_sp.get() == NULL || m_sc.target_sp.get() == curr_frame.m_sc.target_sp.get()); 667 assert (m_sc.module_sp.get() == NULL || curr_frame.m_sc.module_sp.get() == NULL || m_sc.module_sp.get() == curr_frame.m_sc.module_sp.get()); 668 assert (m_sc.comp_unit == NULL || curr_frame.m_sc.comp_unit == NULL || m_sc.comp_unit == curr_frame.m_sc.comp_unit); 669 assert (m_sc.function == NULL || curr_frame.m_sc.function == NULL || m_sc.function == curr_frame.m_sc.function); 670 m_sc = curr_frame.m_sc; 671 m_flags.Clear(GOT_FRAME_BASE | eSymbolContextEverything); 672 m_flags.Set (m_sc.GetResolvedMask()); 673 m_frame_base.Clear(); 674 m_frame_base_error.Clear(); 675 } 676 677 678