summaryrefslogtreecommitdiffstats
path: root/compiler/dwarf/debug_frame_writer.h
blob: b104cc940897ee0b44469c4a684c926e9c909973 (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
/*
 * Copyright (C) 2015 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef ART_COMPILER_DWARF_DEBUG_FRAME_WRITER_H_
#define ART_COMPILER_DWARF_DEBUG_FRAME_WRITER_H_

#include "debug_frame_opcode_writer.h"
#include "dwarf.h"
#include "writer.h"

namespace art {
namespace dwarf {

// Writer for the .eh_frame section (which extends .debug_frame specification).
template<typename Allocator = std::allocator<uint8_t>>
class DebugFrameWriter FINAL : private Writer<Allocator> {
 public:
  void WriteCIE(Reg return_address_register,
                const uint8_t* initial_opcodes,
                int initial_opcodes_size) {
    DCHECK(cie_header_start_ == ~0u);
    cie_header_start_ = this->data()->size();
    if (use_64bit_address_) {
      // TODO: This is not related to being 64bit.
      this->PushUint32(0xffffffff);
      this->PushUint64(0);  // Length placeholder.
      this->PushUint64(0);  // CIE id.
    } else {
      this->PushUint32(0);  // Length placeholder.
      this->PushUint32(0);  // CIE id.
    }
    this->PushUint8(1);   // Version.
    this->PushString("zR");
    this->PushUleb128(DebugFrameOpCodeWriter<Allocator>::kCodeAlignmentFactor);
    this->PushSleb128(DebugFrameOpCodeWriter<Allocator>::kDataAlignmentFactor);
    this->PushUleb128(return_address_register.num());  // ubyte in DWARF2.
    this->PushUleb128(1);  // z: Augmentation data size.
    if (use_64bit_address_) {
      this->PushUint8(0x04);  // R: ((DW_EH_PE_absptr << 4) | DW_EH_PE_udata8).
    } else {
      this->PushUint8(0x03);  // R: ((DW_EH_PE_absptr << 4) | DW_EH_PE_udata4).
    }
    this->PushData(initial_opcodes, initial_opcodes_size);
    this->Pad(use_64bit_address_ ? 8 : 4);
    if (use_64bit_address_) {
      this->UpdateUint64(cie_header_start_ + 4, this->data()->size() - cie_header_start_ - 12);
    } else {
      this->UpdateUint32(cie_header_start_, this->data()->size() - cie_header_start_ - 4);
    }
  }

  void WriteCIE(Reg return_address_register,
                const DebugFrameOpCodeWriter<Allocator>& opcodes) {
    WriteCIE(return_address_register, opcodes.data()->data(), opcodes.data()->size());
  }

  void WriteFDE(uint64_t initial_address,
                uint64_t address_range,
                const uint8_t* unwind_opcodes,
                int unwind_opcodes_size) {
    DCHECK(cie_header_start_ != ~0u);
    size_t fde_header_start = this->data()->size();
    if (use_64bit_address_) {
      // TODO: This is not related to being 64bit.
      this->PushUint32(0xffffffff);
      this->PushUint64(0);  // Length placeholder.
      this->PushUint64(this->data()->size() - cie_header_start_);  // 'CIE_pointer'
    } else {
      this->PushUint32(0);  // Length placeholder.
      this->PushUint32(this->data()->size() - cie_header_start_);  // 'CIE_pointer'
    }
    if (use_64bit_address_) {
      this->PushUint64(initial_address);
      this->PushUint64(address_range);
    } else {
      this->PushUint32(initial_address);
      this->PushUint32(address_range);
    }
    this->PushUleb128(0);  // Augmentation data size.
    this->PushData(unwind_opcodes, unwind_opcodes_size);
    this->Pad(use_64bit_address_ ? 8 : 4);
    if (use_64bit_address_) {
      this->UpdateUint64(fde_header_start + 4, this->data()->size() - fde_header_start - 12);
    } else {
      this->UpdateUint32(fde_header_start, this->data()->size() - fde_header_start - 4);
    }
  }

  DebugFrameWriter(std::vector<uint8_t, Allocator>* buffer, bool use_64bit_address)
      : Writer<Allocator>(buffer),
        use_64bit_address_(use_64bit_address),
        cie_header_start_(~0u) {
  }

 private:
  bool use_64bit_address_;
  size_t cie_header_start_;

  DISALLOW_COPY_AND_ASSIGN(DebugFrameWriter);
};

}  // namespace dwarf
}  // namespace art

#endif  // ART_COMPILER_DWARF_DEBUG_FRAME_WRITER_H_