| 159 | } |
| 160 | |
| 161 | die |
| 162 | value::as_reference() const |
| 163 | { |
| 164 | section_offset off; |
| 165 | // XXX Would be nice if we could avoid this. The cursor is |
| 166 | // all overhead here. |
| 167 | cursor cur(cu->data(), offset); |
| 168 | switch (form) { |
| 169 | case DW_FORM::ref1: |
| 170 | off = cur.fixed<ubyte>(); |
| 171 | break; |
| 172 | case DW_FORM::ref2: |
| 173 | off = cur.fixed<uhalf>(); |
| 174 | break; |
| 175 | case DW_FORM::ref4: |
| 176 | off = cur.fixed<uword>(); |
| 177 | break; |
| 178 | case DW_FORM::ref8: |
| 179 | off = cur.fixed<uint64_t>(); |
| 180 | break; |
| 181 | case DW_FORM::ref_udata: |
| 182 | off = cur.uleb128(); |
| 183 | break; |
| 184 | |
| 185 | case DW_FORM::ref_addr: { |
| 186 | off = cur.offset(); |
| 187 | // These seem to be extremely rare in practice (I |
| 188 | // haven't been able to get gcc to produce a |
| 189 | // ref_addr), so it's not worth caching this lookup. |
| 190 | const compilation_unit *base_cu = nullptr; |
| 191 | for (auto &file_cu : cu->get_dwarf().compilation_units()) { |
| 192 | if (file_cu.get_section_offset() > off) |
| 193 | break; |
| 194 | base_cu = &file_cu; |
| 195 | } |
| 196 | die d(base_cu); |
| 197 | d.read(off - base_cu->get_section_offset()); |
| 198 | return d; |
| 199 | } |
| 200 | |
| 201 | case DW_FORM::ref_sig8: { |
| 202 | uint64_t sig = cur.fixed<uint64_t>(); |
| 203 | try { |
| 204 | return cu->get_dwarf().get_type_unit(sig).type(); |
| 205 | } catch (std::out_of_range &e) { |
| 206 | throw format_error("unknown type signature 0x" + to_hex(sig)); |
| 207 | } |
| 208 | } |
| 209 | |
| 210 | default: |
| 211 | throw value_type_mismatch("cannot read " + to_string(typ) + " as reference"); |
| 212 | } |
| 213 | |
| 214 | die d(cu); |
| 215 | d.read(off); |
| 216 | return d; |
| 217 | } |
| 218 |
no test coverage detected