| /* |
| * Dwarf data format parsing routines. |
| */ |
| |
| #include <u.h> |
| #include <libc.h> |
| #include <bio.h> |
| #include "elf.h" |
| #include "dwarf.h" |
| |
| ulong |
| dwarfget1(DwarfBuf *b) |
| { |
| if(b->p==nil || b->p+1 > b->ep){ |
| b->p = nil; |
| return 0; |
| } |
| return *b->p++; |
| } |
| |
| int |
| dwarfgetn(DwarfBuf *b, uchar *a, int n) |
| { |
| if(b->p==nil || b->p+n > b->ep){ |
| b->p = nil; |
| memset(a, 0, n); |
| return -1; |
| } |
| memmove(a, b->p, n); |
| b->p += n; |
| return 0; |
| } |
| |
| uchar* |
| dwarfgetnref(DwarfBuf *b, ulong n) |
| { |
| uchar *p; |
| |
| if(b->p==nil || b->p+n > b->ep){ |
| b->p = nil; |
| return nil; |
| } |
| p = b->p; |
| b->p += n; |
| return p; |
| } |
| |
| char* |
| dwarfgetstring(DwarfBuf *b) |
| { |
| char *s; |
| |
| if(b->p == nil) |
| return nil; |
| s = (char*)b->p; |
| while(b->p < b->ep && *b->p) |
| b->p++; |
| if(b->p >= b->ep){ |
| b->p = nil; |
| return nil; |
| } |
| b->p++; |
| return s; |
| } |
| |
| void |
| dwarfskip(DwarfBuf *b, int n) |
| { |
| if(b->p==nil || b->p+n > b->ep) |
| b->p = nil; |
| else |
| b->p += n; |
| } |
| |
| ulong |
| dwarfget2(DwarfBuf *b) |
| { |
| ulong v; |
| |
| if(b->p==nil || b->p+2 > b->ep){ |
| b->p = nil; |
| return 0; |
| } |
| v = b->d->elf->hdr.e2(b->p); |
| b->p += 2; |
| return v; |
| } |
| |
| ulong |
| dwarfget4(DwarfBuf *b) |
| { |
| ulong v; |
| |
| if(b->p==nil || b->p+4 > b->ep){ |
| b->p = nil; |
| return 0; |
| } |
| v = b->d->elf->hdr.e4(b->p); |
| b->p += 4; |
| return v; |
| } |
| |
| uvlong |
| dwarfget8(DwarfBuf *b) |
| { |
| uvlong v; |
| |
| if(b->p==nil || b->p+8 > b->ep){ |
| b->p = nil; |
| return 0; |
| } |
| v = b->d->elf->hdr.e8(b->p); |
| b->p += 8; |
| return v; |
| } |
| |
| ulong |
| dwarfgetaddr(DwarfBuf *b) |
| { |
| static int nbad; |
| |
| if(b->addrsize == 0) |
| b->addrsize = b->d->addrsize; |
| |
| switch(b->addrsize){ |
| case 1: |
| return dwarfget1(b); |
| case 2: |
| return dwarfget2(b); |
| case 4: |
| return dwarfget4(b); |
| case 8: |
| return dwarfget8(b); |
| default: |
| if(++nbad == 1) |
| fprint(2, "dwarf: unexpected address size %lud in dwarfgetaddr\n", b->addrsize); |
| b->p = nil; |
| return 0; |
| } |
| } |
| |
| int n1, n2, n3, n4, n5; |
| |
| /* An inline function picks off the calls to dwarfget128 for 1-byte encodings, |
| * more than by far the common case (99.999% on most binaries!). */ |
| ulong |
| dwarfget128(DwarfBuf *b) |
| { |
| static int nbad; |
| ulong c, d; |
| |
| if(b->p == nil) |
| return 0; |
| c = *b->p++; |
| if(!(c&0x80)) |
| {n1++; |
| return c; |
| } |
| c &= ~0x80; |
| d = *b->p++; |
| c |= (d&0x7F)<<7; |
| if(!(d&0x80)) |
| {n2++; |
| return c; |
| } |
| d = *b->p++; |
| c |= (d&0x7F)<<14; |
| if(!(d&0x80)) |
| {n3++; |
| return c; |
| } |
| d = *b->p++; |
| c |= (d&0x7F)<<21; |
| if(!(d&0x80)) |
| {n4++; |
| return c; |
| } |
| d = *b->p++; |
| c |= (d&0x7F)<<28; |
| if(!(d&0x80)) |
| {n5++; |
| return c; |
| } |
| while(b->p<b->ep && *b->p&0x80) |
| b->p++; |
| if(++nbad == 1) |
| fprint(2, "dwarf: overflow during parsing of uleb128 integer\n"); |
| return c; |
| } |
| |
| long |
| dwarfget128s(DwarfBuf *b) |
| { |
| int nb, c; |
| ulong v; |
| static int nbad; |
| |
| v = 0; |
| nb = 0; |
| if(b->p==nil) |
| return 0; |
| while(b->p<b->ep){ |
| c = *b->p++; |
| v |= (c & 0x7F)<<nb; |
| nb += 7; |
| if(!(c&0x80)) |
| break; |
| } |
| if(v&(1<<(nb-1))) |
| v |= ~(((ulong)1<<nb)-1); |
| if(nb > 8*sizeof(ulong)){ |
| if(0) |
| if(++nbad == 1) |
| fprint(2, "dwarf: overflow during parsing of sleb128 integer: got %d bits\n", nb); |
| } |
| return v; |
| } |
| |