summaryrefslogtreecommitdiffstats
path: root/lldb/source/Plugins/Process/Utility/libunwind/src/AssemblyInstructions.hpp
blob: 1e695d5e4f0f20e7537ee7b3933f4b76049a8a02 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
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