fix cursor crash

This commit is contained in:
tqcq 2024-04-07 09:09:54 +00:00
parent 60ff77ec1d
commit 2d12117cfb

View File

@ -4,8 +4,8 @@
#include "internal.hh" #include "internal.hh"
#include <stdexcept>
#include <cstring> #include <cstring>
#include <stdexcept>
using namespace std; using namespace std;
@ -14,57 +14,56 @@ DWARFPP_BEGIN_NAMESPACE
int64_t int64_t
cursor::sleb128() cursor::sleb128()
{ {
// Appendix C // Appendix C
uint64_t result = 0; uint64_t result = 0;
unsigned shift = 0; unsigned shift = 0;
while (pos < sec->end) { while (pos < sec->end) {
uint8_t byte = *(uint8_t*)(pos++); uint8_t byte = *(uint8_t *) (pos++);
result |= (uint64_t)(byte & 0x7f) << shift; result |= (uint64_t) (byte & 0x7f) << shift;
shift += 7; shift += 7;
if ((byte & 0x80) == 0) { if ((byte & 0x80) == 0) {
if (shift < sizeof(result)*8 && (byte & 0x40)) if (shift < sizeof(result) * 8 && (byte & 0x40)) result |= -((uint64_t) 1 << shift);
result |= -((uint64_t)1 << shift); return result;
return result;
}
} }
underflow(); }
return 0; underflow();
return 0;
} }
shared_ptr<section> shared_ptr<section>
cursor::subsection() cursor::subsection()
{ {
// Section 7.4 // Section 7.4
const char *begin = pos; const char *begin = pos;
section_length length = fixed<uword>(); section_length length = fixed<uword>();
format fmt; format fmt;
if (length < 0xfffffff0) { if (length < 0xfffffff0) {
fmt = format::dwarf32; fmt = format::dwarf32;
length += sizeof(uword); length += sizeof(uword);
} else if (length == 0xffffffff) { } else if (length == 0xffffffff) {
length = fixed<uint64_t>(); length = fixed<uint64_t>();
fmt = format::dwarf64; fmt = format::dwarf64;
length += sizeof(uword) + sizeof(uint64_t); length += sizeof(uword) + sizeof(uint64_t);
} else { } else {
throw format_error("initial length has reserved value"); throw format_error("initial length has reserved value");
} }
pos = begin + length; pos = begin + length;
return make_shared<section>(sec->type, begin, length, sec->ord, fmt); return make_shared<section>(sec->type, begin, length, sec->ord, fmt);
} }
void void
cursor::skip_initial_length() cursor::skip_initial_length()
{ {
switch (sec->fmt) { switch (sec->fmt) {
case format::dwarf32: case format::dwarf32:
pos += sizeof(uword); pos += sizeof(uword);
break; break;
case format::dwarf64: case format::dwarf64:
pos += sizeof(uword) + sizeof(uint64_t); pos += sizeof(uword) + sizeof(uint64_t);
break; break;
default: default:
throw logic_error("cannot skip initial length with unknown format"); throw logic_error("cannot skip initial length with unknown format");
} }
} }
void void
@ -76,132 +75,128 @@ cursor::skip_unit_type()
section_offset section_offset
cursor::offset() cursor::offset()
{ {
switch (sec->fmt) { switch (sec->fmt) {
case format::dwarf32: case format::dwarf32:
return fixed<uint32_t>(); return fixed<uint32_t>();
case format::dwarf64: case format::dwarf64:
return fixed<uint64_t>(); return fixed<uint64_t>();
default: default:
throw logic_error("cannot read offset with unknown format"); throw logic_error("cannot read offset with unknown format");
} }
} }
void void
cursor::string(std::string &out) cursor::string(std::string &out)
{ {
size_t size; size_t size;
const char *p = this->cstr(&size); const char *p = this->cstr(&size);
out.resize(size); // out.resize(size);
memmove(&out.front(), p, size); // memmove(&out.front(), p, size);
out = std::string(p, p + size);
} }
const char * const char *
cursor::cstr(size_t *size_out) cursor::cstr(size_t *size_out)
{ {
// Scan string size // Scan string size
const char *p = pos; const char *p = pos;
while (pos < sec->end && *pos) while (pos < sec->end && *pos) pos++;
pos++; if (pos == sec->end) throw format_error("unterminated string");
if (pos == sec->end) if (size_out) *size_out = pos - p;
throw format_error("unterminated string"); pos++;
if (size_out) return p;
*size_out = pos - p;
pos++;
return p;
} }
void void
cursor::skip_form(DW_FORM form) cursor::skip_form(DW_FORM form)
{ {
section_offset tmp; section_offset tmp;
// Section 7.5.4 // Section 7.5.4
switch (form) { switch (form) {
case DW_FORM::addr: case DW_FORM::addr:
pos += sec->addr_size; pos += sec->addr_size;
break; break;
case DW_FORM::sec_offset: case DW_FORM::sec_offset:
case DW_FORM::ref_addr: case DW_FORM::ref_addr:
case DW_FORM::strp: case DW_FORM::strp:
switch (sec->fmt) { switch (sec->fmt) {
case format::dwarf32: case format::dwarf32:
pos += 4; pos += 4;
break; break;
case format::dwarf64: case format::dwarf64:
pos += 8; pos += 8;
break; break;
case format::unknown: case format::unknown:
throw logic_error("cannot read form with unknown format"); throw logic_error("cannot read form with unknown format");
}
break;
// size+data forms
case DW_FORM::block1:
tmp = fixed<ubyte>();
pos += tmp;
break;
case DW_FORM::block2:
tmp = fixed<uhalf>();
pos += tmp;
break;
case DW_FORM::block4:
tmp = fixed<uword>();
pos += tmp;
break;
case DW_FORM::block:
case DW_FORM::exprloc:
tmp = uleb128();
pos += tmp;
break;
// fixed-length forms
case DW_FORM::flag_present:
break;
case DW_FORM::flag:
case DW_FORM::data1:
case DW_FORM::ref1:
pos += 1;
break;
case DW_FORM::data2:
case DW_FORM::ref2:
pos += 2;
break;
case DW_FORM::data4:
case DW_FORM::ref4:
pos += 4;
break;
case DW_FORM::data8:
case DW_FORM::ref_sig8:
pos += 8;
break;
// variable-length forms
case DW_FORM::sdata:
case DW_FORM::udata:
case DW_FORM::ref_udata:
while (pos < sec->end && (*(uint8_t*)pos & 0x80))
pos++;
pos++;
break;
case DW_FORM::string:
while (pos < sec->end && *pos)
pos++;
pos++;
break;
case DW_FORM::indirect:
skip_form((DW_FORM)uleb128());
break;
default:
throw format_error("unknown form " + to_string(form));
} }
break;
// size+data forms
case DW_FORM::block1:
tmp = fixed<ubyte>();
pos += tmp;
break;
case DW_FORM::block2:
tmp = fixed<uhalf>();
pos += tmp;
break;
case DW_FORM::block4:
tmp = fixed<uword>();
pos += tmp;
break;
case DW_FORM::block:
case DW_FORM::exprloc:
tmp = uleb128();
pos += tmp;
break;
// fixed-length forms
case DW_FORM::flag_present:
break;
case DW_FORM::flag:
case DW_FORM::data1:
case DW_FORM::ref1:
pos += 1;
break;
case DW_FORM::data2:
case DW_FORM::ref2:
pos += 2;
break;
case DW_FORM::data4:
case DW_FORM::ref4:
pos += 4;
break;
case DW_FORM::data8:
case DW_FORM::ref_sig8:
pos += 8;
break;
// variable-length forms
case DW_FORM::sdata:
case DW_FORM::udata:
case DW_FORM::ref_udata:
while (pos < sec->end && (*(uint8_t *) pos & 0x80)) pos++;
pos++;
break;
case DW_FORM::string:
while (pos < sec->end && *pos) pos++;
pos++;
break;
case DW_FORM::indirect:
skip_form((DW_FORM) uleb128());
break;
default:
throw format_error("unknown form " + to_string(form));
}
} }
void void
cursor::underflow() cursor::underflow()
{ {
throw underflow_error("cannot read past end of DWARF section"); throw underflow_error("cannot read past end of DWARF section");
} }
DWARFPP_END_NAMESPACE DWARFPP_END_NAMESPACE