eh_frame.cc
Go to the documentation of this file.
1 // Copyright 2016 Google Inc. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "bloaty.h"
16 #include "util.h"
17 #include "absl/strings/string_view.h"
18 #include "dwarf_constants.h"
19 #include "dwarf/dwarf_util.h"
20 
21 using absl::string_view;
22 using namespace dwarf2reader;
23 
24 namespace bloaty {
25 
27  const char* data_base, RangeSink* sink) {
29  const char* ptr = data->data();
31 
32  switch (format) {
33  case DW_EH_PE_omit:
34  return 0;
35  case DW_EH_PE_absptr:
36  if (is_64bit) {
37  value = ReadFixed<uint64_t>(data);
38  } else {
39  value = ReadFixed<uint32_t>(data);
40  }
41  break;
42  case DW_EH_PE_uleb128:
43  value = dwarf::ReadLEB128<uint64_t>(data);
44  break;
45  case DW_EH_PE_udata2:
46  value = ReadFixed<uint16_t>(data);
47  break;
48  case DW_EH_PE_udata4:
49  value = ReadFixed<uint32_t>(data);
50  break;
51  case DW_EH_PE_udata8:
52  value = ReadFixed<uint64_t>(data);
53  break;
54  case DW_EH_PE_sleb128:
55  value = dwarf::ReadLEB128<int64_t>(data);
56  break;
57  case DW_EH_PE_sdata2:
58  value = ReadFixed<int16_t>(data);
59  break;
60  case DW_EH_PE_sdata4:
61  value = ReadFixed<int32_t>(data);
62  break;
63  case DW_EH_PE_sdata8:
64  value = ReadFixed<int64_t>(data);
65  break;
66  default:
67  THROWF("Unexpected eh_frame format value: $0", format);
68  }
69 
71 
72  switch (application) {
73  case 0:
74  break;
75  case DW_EH_PE_pcrel:
76  value += sink->TranslateFileToVM(ptr);
77  break;
78  case DW_EH_PE_datarel:
79  if (data_base == nullptr) {
80  THROW("datarel requested but no data_base provided");
81  }
82  value += sink->TranslateFileToVM(data_base);
83  break;
84  case DW_EH_PE_textrel:
85  case DW_EH_PE_funcrel:
86  case DW_EH_PE_aligned:
87  THROWF("Unimplemented eh_frame application value: $0", application);
88  }
89 
91  string_view location = sink->TranslateVMToFile(value);
92  if (is_64bit) {
93  value = ReadFixed<uint64_t>(&location);
94  } else {
95  value = ReadFixed<uint32_t>(&location);
96  }
97  }
98 
99  return value;
100 }
101 
102 // Code to read the .eh_frame section. This is not technically DWARF, but it
103 // is similar to .debug_frame (which is DWARF) so it's convenient to put it
104 // here.
105 //
106 // The best documentation I can find for this format comes from:
107 //
108 // *
109 // http://refspecs.linuxfoundation.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html
110 // * https://www.airs.com/blog/archives/460
111 //
112 // However these are both under-specified. Some details are not mentioned in
113 // either of these (for example, the fact that the function length uses the FDE
114 // encoding, but always absolute). libdwarf's implementation contains a comment
115 // saying "It is not clear if this is entirely correct". Basically the only
116 // thing you can trust for some of these details is the code that actually
117 // implements unwinding in production:
118 //
119 // * libunwind http://www.nongnu.org/libunwind/
120 // https://github.com/pathscale/libunwind/blob/master/src/dwarf/Gfde.c
121 // * LLVM libunwind (a different project!!)
122 // https://github.com/llvm-mirror/libunwind/blob/master/src/DwarfParser.hpp
123 // * libgcc
124 // https://github.com/gcc-mirror/gcc/blob/master/libgcc/unwind-dw2-fde.c
126  string_view remaining = data;
127 
128  struct CIEInfo {
129  int version = 0;
130  uint32_t code_align = 0;
131  int32_t data_align = 0;
132  uint8_t fde_encoding = 0;
133  uint8_t lsda_encoding = 0;
134  bool is_signal_handler = false;
135  bool has_augmentation_length = false;
136  uint64_t personality_function = 0;
137  uint32_t return_address_reg = 0;
138  };
139 
140  std::unordered_map<const void*, CIEInfo> cie_map;
141 
142  while (remaining.size() > 0) {
144  string_view full_entry = remaining;
145  string_view entry = sizes.ReadInitialLength(&remaining);
146  if (entry.size() == 0 && remaining.size() == 0) {
147  return;
148  }
149  full_entry =
150  full_entry.substr(0, entry.size() + (entry.data() - full_entry.data()));
151  uint32_t id = ReadFixed<uint32_t>(&entry);
152  if (id == 0) {
153  // CIE, we don't attribute this yet.
154  CIEInfo& cie_info = cie_map[full_entry.data()];
155  cie_info.version = ReadFixed<uint8_t>(&entry);
156  string_view aug_string = ReadNullTerminated(&entry);
157  cie_info.code_align = dwarf::ReadLEB128<uint32_t>(&entry);
158  cie_info.data_align = dwarf::ReadLEB128<int32_t>(&entry);
159  switch (cie_info.version) {
160  case 1:
161  cie_info.return_address_reg = ReadFixed<uint8_t>(&entry);
162  break;
163  case 3:
164  cie_info.return_address_reg = dwarf::ReadLEB128<uint32_t>(&entry);
165  break;
166  default:
167  THROW("Unexpected eh_frame CIE version");
168  }
169  while (aug_string.size() > 0) {
170  switch (aug_string[0]) {
171  case 'z':
172  // Length until the end of augmentation data.
173  cie_info.has_augmentation_length = true;
174  dwarf::ReadLEB128<uint32_t>(&entry);
175  break;
176  case 'L':
177  cie_info.lsda_encoding = ReadFixed<uint8_t>(&entry);
178  break;
179  case 'R':
180  cie_info.fde_encoding = ReadFixed<uint8_t>(&entry);
181  break;
182  case 'S':
183  cie_info.is_signal_handler = true;
184  break;
185  case 'P': {
186  uint8_t encoding = ReadFixed<uint8_t>(&entry);
187  cie_info.personality_function =
188  ReadEncodedPointer(encoding, true, &entry, nullptr, sink);
189  break;
190  }
191  default:
192  THROW("Unexepcted augmentation character");
193  }
194  aug_string.remove_prefix(1);
195  }
196  } else {
197  auto iter = cie_map.find(entry.data() - id - 4);
198  if (iter == cie_map.end()) {
199  THROW("Couldn't find CIE for FDE");
200  }
201  const CIEInfo& cie_info = iter->second;
202  // TODO(haberman): don't hard-code 64-bit.
203  uint64_t address = ReadEncodedPointer(cie_info.fde_encoding, true, &entry,
204  nullptr, sink);
205  // TODO(haberman); Technically the FDE addresses could span a
206  // function/compilation unit? They can certainly span inlines.
207  /*
208  uint64_t length =
209  ReadEncodedPointer(cie_info.fde_encoding & 0xf, true, &entry, sink);
210  (void)length;
211 
212  if (cie_info.has_augmentation_length) {
213  uint32_t augmentation_length = dwarf::ReadLEB128<uint32_t>(&entry);
214  (void)augmentation_length;
215  }
216 
217  uint64_t lsda =
218  ReadEncodedPointer(cie_info.lsda_encoding, true, &entry, sink);
219  if (lsda) {
220  }
221  */
222 
223  sink->AddFileRangeForVMAddr("dwarf_fde", address, full_entry);
224  }
225  }
226 }
227 
228 // See documentation here:
229 // http://refspecs.linuxfoundation.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html#EHFRAME
231  const char* base = data.data();
232  uint8_t version = ReadFixed<uint8_t>(&data);
233  uint8_t eh_frame_ptr_enc = ReadFixed<uint8_t>(&data);
234  uint8_t fde_count_enc = ReadFixed<uint8_t>(&data);
235  uint8_t table_enc = ReadFixed<uint8_t>(&data);
236 
237  if (version != 1) {
238  THROWF("Unknown eh_frame_hdr version: $0", version);
239  }
240 
241  // TODO(haberman): don't hard-code 64-bit.
242  uint64_t eh_frame_ptr =
243  ReadEncodedPointer(eh_frame_ptr_enc, true, &data, base, sink);
244  (void)eh_frame_ptr;
245  uint64_t fde_count =
246  ReadEncodedPointer(fde_count_enc, true, &data, base, sink);
247 
248  for (uint64_t i = 0; i < fde_count; i++) {
249  string_view entry_data = data;
250  uint64_t initial_location =
251  ReadEncodedPointer(table_enc, true, &data, base, sink);
252  uint64_t fde_addr = ReadEncodedPointer(table_enc, true, &data, base, sink);
253  entry_data.remove_suffix(data.size());
254  sink->AddFileRangeForVMAddr("dwarf_fde_table", initial_location,
255  entry_data);
256 
257  // We could add fde_addr with an unknown length if we wanted to skip reading
258  // eh_frame. We can't count on this table being available though, so we
259  // don't want to remove the eh_frame reading code altogether.
260  (void)fde_addr;
261  }
262 }
263 
264 } // namespace bloaty
ptr
char * ptr
Definition: abseil-cpp/absl/base/internal/low_level_alloc_test.cc:45
bloaty
Definition: bloaty.cc:69
http2_test_server.format
format
Definition: http2_test_server.py:118
dwarf2reader::DW_EH_PE_sdata8
@ DW_EH_PE_sdata8
Definition: dwarf_constants.h:680
absl::string_view::remove_suffix
ABSL_INTERNAL_STRING_VIEW_CXX14_CONSTEXPR void remove_suffix(size_type n)
Definition: abseil-cpp/absl/strings/string_view.h:354
setup.encoding
encoding
Definition: third_party/protobuf/python/protobuf_distutils/setup.py:40
dwarf2reader::DW_EH_PE_funcrel
@ DW_EH_PE_funcrel
Definition: dwarf_constants.h:686
absl::string_view
Definition: abseil-cpp/absl/strings/string_view.h:167
bloaty.h
dwarf2reader::DW_EH_PE_absptr
@ DW_EH_PE_absptr
Definition: dwarf_constants.h:672
version
Definition: version.py:1
dwarf2reader::DW_EH_PE_uleb128
@ DW_EH_PE_uleb128
Definition: dwarf_constants.h:673
uint8_t
unsigned char uint8_t
Definition: stdint-msvc2008.h:78
uint32_t
unsigned int uint32_t
Definition: stdint-msvc2008.h:80
dwarf2reader::DW_EH_PE_FORMAT_MASK
@ DW_EH_PE_FORMAT_MASK
Definition: dwarf_constants.h:681
dwarf2reader::DW_EH_PE_sleb128
@ DW_EH_PE_sleb128
Definition: dwarf_constants.h:677
absl::string_view::size
constexpr size_type size() const noexcept
Definition: abseil-cpp/absl/strings/string_view.h:277
THROW
#define THROW(msg)
Definition: bloaty/src/util.h:45
dwarf2reader::DW_EH_PE_udata8
@ DW_EH_PE_udata8
Definition: dwarf_constants.h:676
dwarf2reader::DW_EH_PE_omit
@ DW_EH_PE_omit
Definition: dwarf_constants.h:693
dwarf_util.h
dwarf_constants.h
uint64_t
unsigned __int64 uint64_t
Definition: stdint-msvc2008.h:90
bloaty::ReadEncodedPointer
uint64_t ReadEncodedPointer(uint8_t encoding, bool is_64bit, string_view *data, const char *data_base, RangeSink *sink)
Definition: eh_frame.cc:26
bloaty::RangeSink
Definition: bloaty.h:110
bloaty::ReadEhFrameHdr
void ReadEhFrameHdr(absl::string_view contents, RangeSink *sink)
Definition: eh_frame.cc:230
dwarf2reader
Definition: dwarf_constants.h:20
gen_synthetic_protos.base
base
Definition: gen_synthetic_protos.py:31
data
char data[kBufferLength]
Definition: abseil-cpp/absl/strings/internal/str_format/float_conversion.cc:1006
dwarf2reader::DW_EH_PE_APPLICATION_MASK
@ DW_EH_PE_APPLICATION_MASK
Definition: dwarf_constants.h:688
dwarf2reader::DW_EH_PE_sdata2
@ DW_EH_PE_sdata2
Definition: dwarf_constants.h:678
dwarf2reader::DW_EH_PE_udata2
@ DW_EH_PE_udata2
Definition: dwarf_constants.h:674
dwarf2reader::DW_EH_PE_indirect
@ DW_EH_PE_indirect
Definition: dwarf_constants.h:691
dwarf2reader::DW_EH_PE_datarel
@ DW_EH_PE_datarel
Definition: dwarf_constants.h:685
bloaty::dwarf::CompilationUnitSizes
Definition: debug_info.h:88
value
const char * value
Definition: hpack_parser_table.cc:165
bloaty::dwarf::CompilationUnitSizes::ReadInitialLength
absl::string_view ReadInitialLength(absl::string_view *remaining)
Definition: debug_info.cc:74
dwarf2reader::DW_EH_PE_sdata4
@ DW_EH_PE_sdata4
Definition: dwarf_constants.h:679
sink
FormatSinkImpl * sink
Definition: abseil-cpp/absl/strings/internal/str_format/float_conversion.cc:450
absl::string_view::remove_prefix
ABSL_INTERNAL_STRING_VIEW_CXX14_CONSTEXPR void remove_prefix(size_type n)
Definition: abseil-cpp/absl/strings/string_view.h:344
string_view
absl::string_view string_view
Definition: attr.cc:22
bloaty::ReadNullTerminated
absl::string_view ReadNullTerminated(absl::string_view *data)
Definition: third_party/bloaty/src/util.cc:26
dwarf2reader::DW_EH_PE_textrel
@ DW_EH_PE_textrel
Definition: dwarf_constants.h:684
bloaty::ReadEhFrame
void ReadEhFrame(absl::string_view contents, RangeSink *sink)
Definition: eh_frame.cc:125
THROWF
#define THROWF(...)
Definition: bloaty/src/util.h:46
dwarf2reader::DW_EH_PE_aligned
@ DW_EH_PE_aligned
Definition: dwarf_constants.h:687
iter
Definition: test_winkernel.cpp:47
util.h
dwarf2reader::DW_EH_PE_udata4
@ DW_EH_PE_udata4
Definition: dwarf_constants.h:675
dwarf2reader::DW_EH_PE_pcrel
@ DW_EH_PE_pcrel
Definition: dwarf_constants.h:683
int32_t
signed int int32_t
Definition: stdint-msvc2008.h:77
absl::string_view::data
constexpr const_pointer data() const noexcept
Definition: abseil-cpp/absl/strings/string_view.h:336
absl::string_view::substr
constexpr string_view substr(size_type pos=0, size_type n=npos) const
Definition: abseil-cpp/absl/strings/string_view.h:399
i
uint64_t i
Definition: abseil-cpp/absl/container/btree_benchmark.cc:230


grpc
Author(s):
autogenerated on Fri May 16 2025 02:58:18