Files
clang-p2996/lldb/source/Plugins/Process/Utility/libunwind/src/AssemblyInstructions.hpp
2010-06-08 16:52:24 +00:00

148 lines
5.8 KiB
C++

/* -*- 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