LLDB  mainline
UnwindAssemblyInstEmulation.cpp
Go to the documentation of this file.
1 //===-- UnwindAssemblyInstEmulation.cpp --------------------------*- C++-*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
10 
11 #include "lldb/Core/Address.h"
12 #include "lldb/Core/Disassembler.h"
15 #include "lldb/Core/FormatEntity.h"
18 #include "lldb/Target/Process.h"
19 #include "lldb/Target/Target.h"
20 #include "lldb/Target/Thread.h"
21 #include "lldb/Utility/ArchSpec.h"
24 #include "lldb/Utility/Log.h"
25 #include "lldb/Utility/Status.h"
27 
28 using namespace lldb;
29 using namespace lldb_private;
30 
31 // UnwindAssemblyInstEmulation method definitions
32 
34  AddressRange &range, Thread &thread, UnwindPlan &unwind_plan) {
35  std::vector<uint8_t> function_text(range.GetByteSize());
36  ProcessSP process_sp(thread.GetProcess());
37  if (process_sp) {
38  Status error;
39  const bool prefer_file_cache = true;
40  if (process_sp->GetTarget().ReadMemory(
41  range.GetBaseAddress(), prefer_file_cache, function_text.data(),
42  range.GetByteSize(), error) != range.GetByteSize()) {
43  return false;
44  }
45  }
46  return GetNonCallSiteUnwindPlanFromAssembly(
47  range, function_text.data(), function_text.size(), unwind_plan);
48 }
49 
51  AddressRange &range, uint8_t *opcode_data, size_t opcode_size,
52  UnwindPlan &unwind_plan) {
53  if (opcode_data == nullptr || opcode_size == 0)
54  return false;
55 
56  if (range.GetByteSize() > 0 && range.GetBaseAddress().IsValid() &&
57  m_inst_emulator_up.get()) {
58 
59  // The instruction emulation subclass setup the unwind plan for the first
60  // instruction.
61  m_inst_emulator_up->CreateFunctionEntryUnwind(unwind_plan);
62 
63  // CreateFunctionEntryUnwind should have created the first row. If it
64  // doesn't, then we are done.
65  if (unwind_plan.GetRowCount() == 0)
66  return false;
67 
68  const bool prefer_file_cache = true;
69  DisassemblerSP disasm_sp(Disassembler::DisassembleBytes(
70  m_arch, NULL, NULL, range.GetBaseAddress(), opcode_data, opcode_size,
71  99999, prefer_file_cache));
72 
74 
75  if (disasm_sp) {
76 
77  m_range_ptr = &range;
78  m_unwind_plan_ptr = &unwind_plan;
79 
80  const uint32_t addr_byte_size = m_arch.GetAddressByteSize();
81  const bool show_address = true;
82  const bool show_bytes = true;
83  m_inst_emulator_up->GetRegisterInfo(unwind_plan.GetRegisterKind(),
84  unwind_plan.GetInitialCFARegister(),
85  m_cfa_reg_info);
86 
87  m_fp_is_cfa = false;
88  m_register_values.clear();
89  m_pushed_regs.clear();
90 
91  // Initialize the CFA with a known value. In the 32 bit case it will be
92  // 0x80000000, and in the 64 bit case 0x8000000000000000. We use the
93  // address byte size to be safe for any future address sizes
94  m_initial_sp = (1ull << ((addr_byte_size * 8) - 1));
95  RegisterValue cfa_reg_value;
96  cfa_reg_value.SetUInt(m_initial_sp, m_cfa_reg_info.byte_size);
97  SetRegisterValue(m_cfa_reg_info, cfa_reg_value);
98 
99  const InstructionList &inst_list = disasm_sp->GetInstructionList();
100  const size_t num_instructions = inst_list.GetSize();
101 
102  if (num_instructions > 0) {
103  Instruction *inst = inst_list.GetInstructionAtIndex(0).get();
104  const lldb::addr_t base_addr = inst->GetAddress().GetFileAddress();
105 
106  // Map for storing the unwind plan row and the value of the registers
107  // at a given offset. When we see a forward branch we add a new entry
108  // to this map with the actual unwind plan row and register context for
109  // the target address of the branch as the current data have to be
110  // valid for the target address of the branch too if we are in the same
111  // function.
112  std::map<lldb::addr_t, std::pair<UnwindPlan::RowSP, RegisterValueMap>>
113  saved_unwind_states;
114 
115  // Make a copy of the current instruction Row and save it in m_curr_row
116  // so we can add updates as we process the instructions.
117  UnwindPlan::RowSP last_row = unwind_plan.GetLastRow();
118  UnwindPlan::Row *newrow = new UnwindPlan::Row;
119  if (last_row.get())
120  *newrow = *last_row.get();
121  m_curr_row.reset(newrow);
122 
123  // Add the initial state to the save list with offset 0.
124  saved_unwind_states.insert({0, {last_row, m_register_values}});
125 
126  // cache the pc register number (in whatever register numbering this
127  // UnwindPlan uses) for quick reference during instruction parsing.
128  RegisterInfo pc_reg_info;
129  m_inst_emulator_up->GetRegisterInfo(
131 
132  // cache the return address register number (in whatever register
133  // numbering this UnwindPlan uses) for quick reference during
134  // instruction parsing.
135  RegisterInfo ra_reg_info;
136  m_inst_emulator_up->GetRegisterInfo(
138 
139  // The architecture dependent condition code of the last processed
140  // instruction.
142  EmulateInstruction::UnconditionalCondition;
143  lldb::addr_t condition_block_start_offset = 0;
144 
145  for (size_t idx = 0; idx < num_instructions; ++idx) {
146  m_curr_row_modified = false;
147  m_forward_branch_offset = 0;
148 
149  inst = inst_list.GetInstructionAtIndex(idx).get();
150  if (inst) {
151  lldb::addr_t current_offset =
152  inst->GetAddress().GetFileAddress() - base_addr;
153  auto it = saved_unwind_states.upper_bound(current_offset);
154  assert(it != saved_unwind_states.begin() &&
155  "Unwind row for the function entry missing");
156  --it; // Move it to the row corresponding to the current offset
157 
158  // If the offset of m_curr_row don't match with the offset we see
159  // in saved_unwind_states then we have to update m_curr_row and
160  // m_register_values based on the saved values. It is happening
161  // after we processed an epilogue and a return to caller
162  // instruction.
163  if (it->second.first->GetOffset() != m_curr_row->GetOffset()) {
164  UnwindPlan::Row *newrow = new UnwindPlan::Row;
165  *newrow = *it->second.first;
166  m_curr_row.reset(newrow);
167  m_register_values = it->second.second;
168  }
169 
170  m_inst_emulator_up->SetInstruction(inst->GetOpcode(),
171  inst->GetAddress(), nullptr);
172 
173  if (last_condition !=
174  m_inst_emulator_up->GetInstructionCondition()) {
175  if (m_inst_emulator_up->GetInstructionCondition() !=
176  EmulateInstruction::UnconditionalCondition &&
177  saved_unwind_states.count(current_offset) == 0) {
178  // If we don't have a saved row for the current offset then
179  // save our current state because we will have to restore it
180  // after the conditional block.
181  auto new_row =
182  std::make_shared<UnwindPlan::Row>(*m_curr_row.get());
183  saved_unwind_states.insert(
184  {current_offset, {new_row, m_register_values}});
185  }
186 
187  // If the last instruction was conditional with a different
188  // condition then the then current condition then restore the
189  // condition.
190  if (last_condition !=
191  EmulateInstruction::UnconditionalCondition) {
192  const auto &saved_state =
193  saved_unwind_states.at(condition_block_start_offset);
194  m_curr_row =
195  std::make_shared<UnwindPlan::Row>(*saved_state.first);
196  m_curr_row->SetOffset(current_offset);
197  m_register_values = saved_state.second;
198  bool replace_existing =
199  true; // The last instruction might already
200  // created a row for this offset and
201  // we want to overwrite it.
202  unwind_plan.InsertRow(
203  std::make_shared<UnwindPlan::Row>(*m_curr_row),
204  replace_existing);
205  }
206 
207  // We are starting a new conditional block at the actual offset
208  condition_block_start_offset = current_offset;
209  }
210 
211  if (log && log->GetVerbose()) {
212  StreamString strm;
214  FormatEntity::Parse("${frame.pc}: ", format);
215  inst->Dump(&strm, inst_list.GetMaxOpcocdeByteSize(), show_address,
216  show_bytes, NULL, NULL, NULL, &format, 0);
217  log->PutString(strm.GetString());
218  }
219 
220  last_condition = m_inst_emulator_up->GetInstructionCondition();
221 
222  m_inst_emulator_up->EvaluateInstruction(
223  eEmulateInstructionOptionIgnoreConditions);
224 
225  // If the current instruction is a branch forward then save the
226  // current CFI information for the offset where we are branching.
227  if (m_forward_branch_offset != 0 &&
229  m_forward_branch_offset)) {
230  auto newrow =
231  std::make_shared<UnwindPlan::Row>(*m_curr_row.get());
232  newrow->SetOffset(current_offset + m_forward_branch_offset);
233  saved_unwind_states.insert(
234  {current_offset + m_forward_branch_offset,
235  {newrow, m_register_values}});
236  unwind_plan.InsertRow(newrow);
237  }
238 
239  // Were there any changes to the CFI while evaluating this
240  // instruction?
241  if (m_curr_row_modified) {
242  // Save the modified row if we don't already have a CFI row in
243  // the current address
244  if (saved_unwind_states.count(
245  current_offset + inst->GetOpcode().GetByteSize()) == 0) {
246  m_curr_row->SetOffset(current_offset +
247  inst->GetOpcode().GetByteSize());
248  unwind_plan.InsertRow(m_curr_row);
249  saved_unwind_states.insert(
250  {current_offset + inst->GetOpcode().GetByteSize(),
251  {m_curr_row, m_register_values}});
252 
253  // Allocate a new Row for m_curr_row, copy the current state
254  // into it
255  UnwindPlan::Row *newrow = new UnwindPlan::Row;
256  *newrow = *m_curr_row.get();
257  m_curr_row.reset(newrow);
258  }
259  }
260  }
261  }
262  }
263  }
264 
265  if (log && log->GetVerbose()) {
266  StreamString strm;
267  lldb::addr_t base_addr = range.GetBaseAddress().GetFileAddress();
268  strm.Printf("Resulting unwind rows for [0x%" PRIx64 " - 0x%" PRIx64 "):",
269  base_addr, base_addr + range.GetByteSize());
270  unwind_plan.Dump(strm, nullptr, base_addr);
271  log->PutString(strm.GetString());
272  }
273  return unwind_plan.GetRowCount() > 0;
274  }
275  return false;
276 }
277 
279  AddressRange &func, Thread &thread, UnwindPlan &unwind_plan) {
280  return false;
281 }
282 
284  Thread &thread,
285  UnwindPlan &unwind_plan) {
286  return false;
287 }
288 
290  AddressRange &func, const ExecutionContext &exe_ctx,
291  Address &first_non_prologue_insn) {
292  return false;
293 }
294 
297  std::unique_ptr<EmulateInstruction> inst_emulator_up(
298  EmulateInstruction::FindPlugin(arch, eInstructionTypePrologueEpilogue,
299  NULL));
300  // Make sure that all prologue instructions are handled
301  if (inst_emulator_up)
302  return new UnwindAssemblyInstEmulation(arch, inst_emulator_up.release());
303  return NULL;
304 }
305 
306 // PluginInterface protocol in UnwindAssemblyParser_x86
308  return GetPluginNameStatic();
309 }
310 
312 
314  PluginManager::RegisterPlugin(GetPluginNameStatic(),
315  GetPluginDescriptionStatic(), CreateInstance);
316 }
317 
319  PluginManager::UnregisterPlugin(CreateInstance);
320 }
321 
323  static ConstString g_name("inst-emulation");
324  return g_name;
325 }
326 
328  return "Instruction emulation based unwind information.";
329 }
330 
331 uint64_t UnwindAssemblyInstEmulation::MakeRegisterKindValuePair(
332  const RegisterInfo &reg_info) {
333  lldb::RegisterKind reg_kind;
334  uint32_t reg_num;
335  if (EmulateInstruction::GetBestRegisterKindAndNumber(&reg_info, reg_kind,
336  reg_num))
337  return (uint64_t)reg_kind << 24 | reg_num;
338  return 0ull;
339 }
340 
341 void UnwindAssemblyInstEmulation::SetRegisterValue(
342  const RegisterInfo &reg_info, const RegisterValue &reg_value) {
343  m_register_values[MakeRegisterKindValuePair(reg_info)] = reg_value;
344 }
345 
346 bool UnwindAssemblyInstEmulation::GetRegisterValue(const RegisterInfo &reg_info,
347  RegisterValue &reg_value) {
348  const uint64_t reg_id = MakeRegisterKindValuePair(reg_info);
349  RegisterValueMap::const_iterator pos = m_register_values.find(reg_id);
350  if (pos != m_register_values.end()) {
351  reg_value = pos->second;
352  return true; // We had a real value that comes from an opcode that wrote
353  // to it...
354  }
355  // We are making up a value that is recognizable...
356  reg_value.SetUInt(reg_id, reg_info.byte_size);
357  return false;
358 }
359 
360 size_t UnwindAssemblyInstEmulation::ReadMemory(
361  EmulateInstruction *instruction, void *baton,
362  const EmulateInstruction::Context &context, lldb::addr_t addr, void *dst,
363  size_t dst_len) {
365 
366  if (log && log->GetVerbose()) {
367  StreamString strm;
368  strm.Printf(
369  "UnwindAssemblyInstEmulation::ReadMemory (addr = 0x%16.16" PRIx64
370  ", dst = %p, dst_len = %" PRIu64 ", context = ",
371  addr, dst, (uint64_t)dst_len);
372  context.Dump(strm, instruction);
373  log->PutString(strm.GetString());
374  }
375  memset(dst, 0, dst_len);
376  return dst_len;
377 }
378 
379 size_t UnwindAssemblyInstEmulation::WriteMemory(
380  EmulateInstruction *instruction, void *baton,
381  const EmulateInstruction::Context &context, lldb::addr_t addr,
382  const void *dst, size_t dst_len) {
383  if (baton && dst && dst_len)
384  return ((UnwindAssemblyInstEmulation *)baton)
385  ->WriteMemory(instruction, context, addr, dst, dst_len);
386  return 0;
387 }
388 
389 size_t UnwindAssemblyInstEmulation::WriteMemory(
390  EmulateInstruction *instruction, const EmulateInstruction::Context &context,
391  lldb::addr_t addr, const void *dst, size_t dst_len) {
392  DataExtractor data(dst, dst_len,
393  instruction->GetArchitecture().GetByteOrder(),
394  instruction->GetArchitecture().GetAddressByteSize());
395 
397 
398  if (log && log->GetVerbose()) {
399  StreamString strm;
400 
401  strm.PutCString("UnwindAssemblyInstEmulation::WriteMemory (");
402  DumpDataExtractor(data, &strm, 0, eFormatBytes, 1, dst_len, UINT32_MAX,
403  addr, 0, 0);
404  strm.PutCString(", context = ");
405  context.Dump(strm, instruction);
406  log->PutString(strm.GetString());
407  }
408 
409  const bool cant_replace = false;
410 
411  switch (context.type) {
412  default:
413  case EmulateInstruction::eContextInvalid:
414  case EmulateInstruction::eContextReadOpcode:
415  case EmulateInstruction::eContextImmediate:
416  case EmulateInstruction::eContextAdjustBaseRegister:
417  case EmulateInstruction::eContextRegisterPlusOffset:
418  case EmulateInstruction::eContextAdjustPC:
419  case EmulateInstruction::eContextRegisterStore:
420  case EmulateInstruction::eContextRegisterLoad:
421  case EmulateInstruction::eContextRelativeBranchImmediate:
422  case EmulateInstruction::eContextAbsoluteBranchRegister:
423  case EmulateInstruction::eContextSupervisorCall:
424  case EmulateInstruction::eContextTableBranchReadMemory:
425  case EmulateInstruction::eContextWriteRegisterRandomBits:
426  case EmulateInstruction::eContextWriteMemoryRandomBits:
427  case EmulateInstruction::eContextArithmetic:
428  case EmulateInstruction::eContextAdvancePC:
429  case EmulateInstruction::eContextReturnFromException:
430  case EmulateInstruction::eContextPopRegisterOffStack:
431  case EmulateInstruction::eContextAdjustStackPointer:
432  break;
433 
434  case EmulateInstruction::eContextPushRegisterOnStack: {
435  uint32_t reg_num = LLDB_INVALID_REGNUM;
436  uint32_t generic_regnum = LLDB_INVALID_REGNUM;
437  assert(context.info_type ==
438  EmulateInstruction::eInfoTypeRegisterToRegisterPlusOffset &&
439  "unhandled case, add code to handle this!");
440  const uint32_t unwind_reg_kind = m_unwind_plan_ptr->GetRegisterKind();
441  reg_num = context.info.RegisterToRegisterPlusOffset.data_reg
442  .kinds[unwind_reg_kind];
443  generic_regnum = context.info.RegisterToRegisterPlusOffset.data_reg
444  .kinds[eRegisterKindGeneric];
445 
446  if (reg_num != LLDB_INVALID_REGNUM &&
447  generic_regnum != LLDB_REGNUM_GENERIC_SP) {
448  if (m_pushed_regs.find(reg_num) == m_pushed_regs.end()) {
449  m_pushed_regs[reg_num] = addr;
450  const int32_t offset = addr - m_initial_sp;
451  m_curr_row->SetRegisterLocationToAtCFAPlusOffset(reg_num, offset,
452  cant_replace);
453  m_curr_row_modified = true;
454  }
455  }
456  } break;
457  }
458 
459  return dst_len;
460 }
461 
462 bool UnwindAssemblyInstEmulation::ReadRegister(EmulateInstruction *instruction,
463  void *baton,
464  const RegisterInfo *reg_info,
465  RegisterValue &reg_value) {
466 
467  if (baton && reg_info)
468  return ((UnwindAssemblyInstEmulation *)baton)
469  ->ReadRegister(instruction, reg_info, reg_value);
470  return false;
471 }
472 bool UnwindAssemblyInstEmulation::ReadRegister(EmulateInstruction *instruction,
473  const RegisterInfo *reg_info,
474  RegisterValue &reg_value) {
475  bool synthetic = GetRegisterValue(*reg_info, reg_value);
476 
478 
479  if (log && log->GetVerbose()) {
480 
481  StreamString strm;
482  strm.Printf("UnwindAssemblyInstEmulation::ReadRegister (name = \"%s\") => "
483  "synthetic_value = %i, value = ",
484  reg_info->name, synthetic);
485  DumpRegisterValue(reg_value, &strm, reg_info, false, false, eFormatDefault);
486  log->PutString(strm.GetString());
487  }
488  return true;
489 }
490 
491 bool UnwindAssemblyInstEmulation::WriteRegister(
492  EmulateInstruction *instruction, void *baton,
493  const EmulateInstruction::Context &context, const RegisterInfo *reg_info,
494  const RegisterValue &reg_value) {
495  if (baton && reg_info)
496  return ((UnwindAssemblyInstEmulation *)baton)
497  ->WriteRegister(instruction, context, reg_info, reg_value);
498  return false;
499 }
500 bool UnwindAssemblyInstEmulation::WriteRegister(
501  EmulateInstruction *instruction, const EmulateInstruction::Context &context,
502  const RegisterInfo *reg_info, const RegisterValue &reg_value) {
504 
505  if (log && log->GetVerbose()) {
506 
507  StreamString strm;
508  strm.Printf(
509  "UnwindAssemblyInstEmulation::WriteRegister (name = \"%s\", value = ",
510  reg_info->name);
511  DumpRegisterValue(reg_value, &strm, reg_info, false, false, eFormatDefault);
512  strm.PutCString(", context = ");
513  context.Dump(strm, instruction);
514  log->PutString(strm.GetString());
515  }
516 
517  SetRegisterValue(*reg_info, reg_value);
518 
519  switch (context.type) {
520  case EmulateInstruction::eContextInvalid:
521  case EmulateInstruction::eContextReadOpcode:
522  case EmulateInstruction::eContextImmediate:
523  case EmulateInstruction::eContextAdjustBaseRegister:
524  case EmulateInstruction::eContextRegisterPlusOffset:
525  case EmulateInstruction::eContextAdjustPC:
526  case EmulateInstruction::eContextRegisterStore:
527  case EmulateInstruction::eContextSupervisorCall:
528  case EmulateInstruction::eContextTableBranchReadMemory:
529  case EmulateInstruction::eContextWriteRegisterRandomBits:
530  case EmulateInstruction::eContextWriteMemoryRandomBits:
531  case EmulateInstruction::eContextAdvancePC:
532  case EmulateInstruction::eContextReturnFromException:
533  case EmulateInstruction::eContextPushRegisterOnStack:
534  case EmulateInstruction::eContextRegisterLoad:
535  // {
536  // const uint32_t reg_num =
537  // reg_info->kinds[m_unwind_plan_ptr->GetRegisterKind()];
538  // if (reg_num != LLDB_INVALID_REGNUM)
539  // {
540  // const bool can_replace_only_if_unspecified = true;
541  //
542  // m_curr_row.SetRegisterLocationToUndefined (reg_num,
543  // can_replace_only_if_unspecified,
544  // can_replace_only_if_unspecified);
545  // m_curr_row_modified = true;
546  // }
547  // }
548  break;
549 
550  case EmulateInstruction::eContextArithmetic: {
551  // If we adjusted the current frame pointer by a constant then adjust the
552  // CFA offset
553  // with the same amount.
554  lldb::RegisterKind kind = m_unwind_plan_ptr->GetRegisterKind();
555  if (m_fp_is_cfa && reg_info->kinds[kind] == m_cfa_reg_info.kinds[kind] &&
556  context.info_type == EmulateInstruction::eInfoTypeRegisterPlusOffset &&
557  context.info.RegisterPlusOffset.reg.kinds[kind] ==
558  m_cfa_reg_info.kinds[kind]) {
559  const int64_t offset = context.info.RegisterPlusOffset.signed_offset;
560  m_curr_row->GetCFAValue().IncOffset(-1 * offset);
561  m_curr_row_modified = true;
562  }
563  } break;
564 
565  case EmulateInstruction::eContextAbsoluteBranchRegister:
566  case EmulateInstruction::eContextRelativeBranchImmediate: {
567  if (context.info_type == EmulateInstruction::eInfoTypeISAAndImmediate &&
568  context.info.ISAAndImmediate.unsigned_data32 > 0) {
569  m_forward_branch_offset =
570  context.info.ISAAndImmediateSigned.signed_data32;
571  } else if (context.info_type ==
572  EmulateInstruction::eInfoTypeISAAndImmediateSigned &&
573  context.info.ISAAndImmediateSigned.signed_data32 > 0) {
574  m_forward_branch_offset = context.info.ISAAndImmediate.unsigned_data32;
575  } else if (context.info_type == EmulateInstruction::eInfoTypeImmediate &&
576  context.info.unsigned_immediate > 0) {
577  m_forward_branch_offset = context.info.unsigned_immediate;
578  } else if (context.info_type ==
579  EmulateInstruction::eInfoTypeImmediateSigned &&
580  context.info.signed_immediate > 0) {
581  m_forward_branch_offset = context.info.signed_immediate;
582  }
583  } break;
584 
585  case EmulateInstruction::eContextPopRegisterOffStack: {
586  const uint32_t reg_num =
587  reg_info->kinds[m_unwind_plan_ptr->GetRegisterKind()];
588  const uint32_t generic_regnum = reg_info->kinds[eRegisterKindGeneric];
589  if (reg_num != LLDB_INVALID_REGNUM &&
590  generic_regnum != LLDB_REGNUM_GENERIC_SP) {
591  switch (context.info_type) {
592  case EmulateInstruction::eInfoTypeAddress:
593  if (m_pushed_regs.find(reg_num) != m_pushed_regs.end() &&
594  context.info.address == m_pushed_regs[reg_num]) {
595  m_curr_row->SetRegisterLocationToSame(reg_num,
596  false /*must_replace*/);
597  m_curr_row_modified = true;
598  }
599  break;
600  case EmulateInstruction::eInfoTypeISA:
601  assert(
602  (generic_regnum == LLDB_REGNUM_GENERIC_PC ||
603  generic_regnum == LLDB_REGNUM_GENERIC_FLAGS) &&
604  "eInfoTypeISA used for popping a register other the PC/FLAGS");
605  if (generic_regnum != LLDB_REGNUM_GENERIC_FLAGS) {
606  m_curr_row->SetRegisterLocationToSame(reg_num,
607  false /*must_replace*/);
608  m_curr_row_modified = true;
609  }
610  break;
611  default:
612  assert(false && "unhandled case, add code to handle this!");
613  break;
614  }
615  }
616  } break;
617 
618  case EmulateInstruction::eContextSetFramePointer:
619  if (!m_fp_is_cfa) {
620  m_fp_is_cfa = true;
621  m_cfa_reg_info = *reg_info;
622  const uint32_t cfa_reg_num =
623  reg_info->kinds[m_unwind_plan_ptr->GetRegisterKind()];
624  assert(cfa_reg_num != LLDB_INVALID_REGNUM);
625  m_curr_row->GetCFAValue().SetIsRegisterPlusOffset(
626  cfa_reg_num, m_initial_sp - reg_value.GetAsUInt64());
627  m_curr_row_modified = true;
628  }
629  break;
630 
631  case EmulateInstruction::eContextRestoreStackPointer:
632  if (m_fp_is_cfa) {
633  m_fp_is_cfa = false;
634  m_cfa_reg_info = *reg_info;
635  const uint32_t cfa_reg_num =
636  reg_info->kinds[m_unwind_plan_ptr->GetRegisterKind()];
637  assert(cfa_reg_num != LLDB_INVALID_REGNUM);
638  m_curr_row->GetCFAValue().SetIsRegisterPlusOffset(
639  cfa_reg_num, m_initial_sp - reg_value.GetAsUInt64());
640  m_curr_row_modified = true;
641  }
642  break;
643 
644  case EmulateInstruction::eContextAdjustStackPointer:
645  // If we have created a frame using the frame pointer, don't follow
646  // subsequent adjustments to the stack pointer.
647  if (!m_fp_is_cfa) {
648  m_curr_row->GetCFAValue().SetIsRegisterPlusOffset(
649  m_curr_row->GetCFAValue().GetRegisterNumber(),
650  m_initial_sp - reg_value.GetAsUInt64());
651  m_curr_row_modified = true;
652  }
653  break;
654  }
655  return true;
656 }
size_t PutCString(llvm::StringRef cstr)
Output a C string to the stream.
Definition: Stream.cpp:61
void SetOffset(lldb::addr_t offset)
Definition: UnwindPlan.h:327
#define LLDB_REGNUM_GENERIC_PC
Definition: lldb-defines.h:63
An data extractor class.
Definition: DataExtractor.h:47
lldb::RegisterKind GetRegisterKind() const
Definition: UnwindPlan.h:406
Enumerations for broadcasting.
Definition: SBLaunchInfo.h:14
lldb::addr_t GetByteSize() const
Get accessor for the byte size of this range.
Definition: AddressRange.h:232
void InsertRow(const RowSP &row_sp, bool replace_existing=false)
Definition: UnwindPlan.cpp:363
void Dump(Stream &s, EmulateInstruction *instruction) const
uint32_t GetInitialCFARegister() const
Definition: UnwindPlan.h:416
uint32_t GetAddressByteSize() const
Returns the size in bytes of an address of the current architecture.
Definition: ArchSpec.cpp:742
#define LLDB_REGNUM_GENERIC_RA
Definition: lldb-defines.h:66
virtual void Dump(Stream *s, uint32_t max_opcode_byte_size, bool show_address, bool show_bytes, const ExecutionContext *exe_ctx, const SymbolContext *sym_ctx, const SymbolContext *prev_sym_ctx, const FormatEntity::Entry *disassembly_addr_format, size_t max_address_text_size)
Dump the text representation of this Instruction to a Stream.
bool GetNonCallSiteUnwindPlanFromAssembly(lldb_private::AddressRange &func, lldb_private::Thread &thread, lldb_private::UnwindPlan &unwind_plan) override
void PutString(llvm::StringRef str)
Definition: Log.cpp:110
bool ContainsFileAddress(const Address &so_addr) const
Check if a section offset address is contained in this range.
An architecture specification class.
Definition: ArchSpec.h:32
bool AugmentUnwindPlanFromCallSite(lldb_private::AddressRange &func, lldb_private::Thread &thread, lldb_private::UnwindPlan &unwind_plan) override
lldb::addr_t GetFileAddress() const
Get the file address.
Definition: Address.cpp:272
"lldb/Target/ExecutionContext.h" A class that contains an execution context.
static const char * GetPluginDescriptionStatic()
#define LLDB_REGNUM_GENERIC_SP
Definition: lldb-defines.h:64
#define LIBLLDB_LOG_UNWIND
Definition: Logging.h:29
"lldb/Core/EmulateInstruction.h" A class that allows emulation of CPU opcodes.
bool GetFastUnwindPlan(lldb_private::AddressRange &func, lldb_private::Thread &thread, lldb_private::UnwindPlan &unwind_plan) override
uint64_t GetAsUInt64(uint64_t fail_value=UINT64_MAX, bool *success_ptr=nullptr) const
static lldb_private::UnwindAssembly * CreateInstance(const lldb_private::ArchSpec &arch)
bool SetUInt(uint64_t uint, uint32_t byte_size)
bool DumpRegisterValue(const RegisterValue &reg_val, Stream *s, const RegisterInfo *reg_info, bool prefix_with_name, bool prefix_with_alt_name, lldb::Format format, uint32_t reg_name_right_align_at=0)
#define UINT32_MAX
Definition: lldb-defines.h:31
union lldb_private::EmulateInstruction::Context::@5 info
const Opcode & GetOpcode() const
Definition: Disassembler.h:196
Node * Parse(llvm::StringRef expr, llvm::BumpPtrAllocator &alloc)
Parse the given postfix expression.
Log * GetLogIfAllCategoriesSet(uint32_t mask)
Definition: Logging.cpp:57
const ArchSpec & GetArchitecture() const
std::shared_ptr< Row > RowSP
Definition: UnwindPlan.h:366
llvm::StringRef GetString() const
lldb::ByteOrder GetByteOrder() const
Returns the byte order for the architecture specification.
Definition: ArchSpec.cpp:788
#define LLDB_REGNUM_GENERIC_FLAGS
Definition: lldb-defines.h:67
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
Definition: Stream.cpp:106
bool GetVerbose() const
Definition: Log.cpp:250
struct lldb_private::EmulateInstruction::Context::@5::RegisterToRegisterPlusOffset RegisterToRegisterPlusOffset
A section + offset based address class.
Definition: Address.h:80
bool IsValid() const
Check if the object state is valid.
Definition: Address.h:343
uint32_t GetByteSize() const
Definition: Opcode.h:207
lldb::ProcessSP GetProcess() const
Definition: Thread.h:154
void Dump(Stream &s, Thread *thread, lldb::addr_t base_addr) const
Definition: UnwindPlan.cpp:484
lldb::offset_t DumpDataExtractor(const DataExtractor &DE, Stream *s, lldb::offset_t offset, lldb::Format item_format, size_t item_byte_size, size_t item_count, size_t num_per_line, uint64_t base_addr, uint32_t item_bit_size, uint32_t item_bit_offset, ExecutionContextScope *exe_scope=nullptr)
Dumps item_count objects into the stream s.
uint32_t GetMaxOpcocdeByteSize() const
lldb::InstructionSP GetInstructionAtIndex(size_t idx) const
const UnwindPlan::RowSP GetLastRow() const
Definition: UnwindPlan.cpp:413
uint64_t addr_t
Definition: lldb-types.h:83
bool GetRegisterInfo(uint32_t reg_num, RegisterLocation &register_location) const
Definition: UnwindPlan.cpp:249
struct lldb_private::EmulateInstruction::Context::@5::RegisterPlusOffset RegisterPlusOffset
A uniqued constant string class.
Definition: ConstString.h:38
static lldb_private::ConstString GetPluginNameStatic()
Definition: SBAddress.h:15
lldb_private::ConstString GetPluginName() override
Address & GetBaseAddress()
Get accessor for the base address of the range.
Definition: AddressRange.h:220
struct lldb_private::EmulateInstruction::Context::@5::ISAAndImmediateSigned ISAAndImmediateSigned
A section + offset based address range class.
Definition: AddressRange.h:32
struct lldb_private::EmulateInstruction::Context::@5::ISAAndImmediate ISAAndImmediate
const Address & GetAddress() const
Definition: Disassembler.h:84
bool FirstNonPrologueInsn(lldb_private::AddressRange &func, const lldb_private::ExecutionContext &exe_ctx, lldb_private::Address &first_non_prologue_insn) override
An error handling class.
Definition: Status.h:44
#define LLDB_INVALID_REGNUM
Definition: lldb-defines.h:90