summaryrefslogtreecommitdiffstats
path: root/lldb/source/Plugins/Process/Utility/libunwind/src/AssemblyInstructions.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/source/Plugins/Process/Utility/libunwind/src/AssemblyInstructions.hpp')
-rw-r--r--lldb/source/Plugins/Process/Utility/libunwind/src/AssemblyInstructions.hpp147
1 files changed, 147 insertions, 0 deletions
diff --git a/lldb/source/Plugins/Process/Utility/libunwind/src/AssemblyInstructions.hpp b/lldb/source/Plugins/Process/Utility/libunwind/src/AssemblyInstructions.hpp
new file mode 100644
index 00000000000..1e695d5e4f0
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/libunwind/src/AssemblyInstructions.hpp
@@ -0,0 +1,147 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 vi:set tabstop=4 expandtab: -*/
+//===-- AssemblyInstructions.hpp --------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __ASSEMBLY_INSTRUCTIONS_HPP
+#define __ASSEMBLY_INSTRUCTIONS_HPP
+
+#if defined (SUPPORT_REMOTE_UNWINDING)
+
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS
+#endif
+#ifndef __STDC_CONSTANT_MACROS
+#define __STDC_CONSTANT_MACROS
+#endif
+
+#include <limits.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <map>
+
+#include "libunwind.h"
+#include "AssemblyParser.hpp"
+#include "AddressSpace.hpp"
+#include "Registers.hpp"
+#include "RemoteUnwindProfile.h"
+
+namespace lldb_private
+{
+
+// A debug function to dump the contents of an RemoteUnwindProfile to
+// stdout in a human readable form.
+
+template <typename A, typename R>
+void printProfile (A& addressSpace, uint64_t pc, RemoteUnwindProfile* profile, R& registers) {
+ RemoteProcInfo *procinfo = addressSpace.getRemoteProcInfo();
+ RemoteRegisterMap *regmap = procinfo->getRegisterMap();
+
+ procinfo->logDebug ("Print profile: given pc of 0x%llx, profile has range 0x%llx - 0x%llx", pc, profile->fStart, profile->fEnd);
+ procinfo->logDebug ("CFA locations:");
+ std::map<uint64_t, RemoteUnwindProfile::CFALocation>::iterator i;
+ for (i = profile->cfa.begin(); i != profile->cfa.end(); ++i) {
+ procinfo->logDebug (" as of 0x%llx cfa is based off of reg %d (%s) offset %d", i->first, i->second.regno, regmap->unwind_regno_to_name(i->second.regno), i->second.offset);
+ }
+ procinfo->logDebug ("Caller's saved IP is at %d bytes offset from the cfa", (int)profile->returnAddress.value);
+ procinfo->logDebug ("Register saves:");
+ std::map<uint64_t, std::vector<RemoteUnwindProfile::SavedReg> >::iterator j;
+ for (j = profile->saved_registers.begin(); j != profile->saved_registers.end(); ++j) {
+ char *tbuf1, *tbuf2, *tbuf3;
+ asprintf (&tbuf1, " at pc 0x%llx there are %d registers saved ", j->first, (int) j->second.size());
+ std::vector<RemoteUnwindProfile::SavedReg>::iterator k;
+ for (k = j->second.begin(); k != j->second.end(); ++k) {
+ if (k->location == RemoteUnwindProfile::kRegisterOffsetFromCFA) {
+ asprintf (&tbuf2, "[reg %d (%s) is %d bytes from cfa] ", k->regno, regmap->unwind_regno_to_name(k->regno), (int) k->value);
+ int newlen = strlen (tbuf1) + strlen (tbuf2) + 1;
+ tbuf3 = (char *) malloc (newlen);
+ strcpy (tbuf3, tbuf1);
+ strcat (tbuf3, tbuf2);
+ free (tbuf1);
+ free (tbuf2);
+ tbuf1 = tbuf3;
+ }
+ if (k->location == RemoteUnwindProfile::kRegisterIsCFA) {
+ asprintf (&tbuf2, "[reg %d (%s) is the same as the cfa] ", k->regno, regmap->unwind_regno_to_name(k->regno));
+ int newlen = strlen (tbuf1) + strlen (tbuf2) + 1;
+ tbuf3 = (char *) malloc (newlen);
+ strcpy (tbuf3, tbuf1);
+ strcat (tbuf3, tbuf2);
+ free (tbuf1);
+ free (tbuf2);
+ tbuf1 = tbuf3;
+ }
+ }
+ procinfo->logDebug ("%s", tbuf1);
+ free (tbuf1);
+ }
+}
+
+template <typename A, typename R>
+int stepWithAssembly (A& addressSpace, uint64_t pc, RemoteUnwindProfile* profile, R& registers) {
+ R newRegisters(registers);
+ RemoteProcInfo *procinfo = addressSpace.getRemoteProcInfo();
+ if (pc > profile->fEnd)
+ ABORT("stepWithAssembly called with pc not in RemoteUnwindProfile's bounds");
+
+ if (procinfo && (procinfo->getDebugLoggingLevel() & UNW_LOG_LEVEL_DEBUG))
+ printProfile (addressSpace, pc, profile, registers);
+
+ std::map<uint64_t, RemoteUnwindProfile::CFALocation>::iterator i = profile->cfa.lower_bound (pc);
+ if (i == profile->cfa.begin() && i == profile->cfa.end())
+ return UNW_EINVAL;
+ if (i == profile->cfa.end()) {
+ --i;
+ } else {
+ if (i != profile->cfa.begin() && i->first != pc)
+ --i;
+ }
+
+ uint64_t cfa = registers.getRegister (i->second.regno) + i->second.offset;
+
+ std::map<uint64_t, std::vector<RemoteUnwindProfile::SavedReg> >::iterator j;
+
+ for (j = profile->saved_registers.begin(); j != profile->saved_registers.end() && j->first <= pc; ++j) {
+ std::vector<RemoteUnwindProfile::SavedReg>::iterator k = j->second.begin();
+ for (; k != j->second.end(); ++k) {
+ RemoteUnwindProfile::SavedReg sr = *k;
+ if (sr.type == RemoteUnwindProfile::kGeneralPurposeRegister) {
+ uint64_t result;
+ int err = 0;
+ switch (sr.location) {
+ case RemoteUnwindProfile::kRegisterOffsetFromCFA:
+ result = addressSpace.getP(cfa + sr.value, err);
+ break;
+ case RemoteUnwindProfile::kRegisterIsCFA:
+ result = cfa;
+ break;
+ default:
+ ABORT("Unknown saved register location in stepWithAssembly.");
+ }
+ // If we failed to read remote memory, stop unwinding.
+ if (err)
+ return UNW_STEP_END;
+ newRegisters.setRegister (sr.regno, result);
+ }
+ }
+ }
+ newRegisters.setSP(cfa);
+ uint64_t ip = addressSpace.getP(cfa + profile->returnAddress.value);
+ if (ip == 0)
+ return UNW_STEP_END;
+ newRegisters.setIP(ip);
+ registers = newRegisters;
+ return UNW_STEP_SUCCESS;
+}
+
+}; // namespace lldb_private
+
+#endif // SUPPORT_REMOTE_UNWINDING
+#endif //ASSEMBLY_INSTRUCTIONS_HPP
OpenPOWER on IntegriCloud