]> Cypherpunks repositories - gostls13.git/commitdiff
6l/8l: emit DWARF frame info.
authorLuuk van Dijk <lvd@golang.org>
Mon, 20 Sep 2010 16:44:19 +0000 (18:44 +0200)
committerLuuk van Dijk <lvd@golang.org>
Mon, 20 Sep 2010 16:44:19 +0000 (18:44 +0200)
R=rsc, ken2, r
CC=golang-dev
https://golang.org/cl/2151044

src/cmd/6l/l.h
src/cmd/6l/pass.c
src/cmd/8l/l.h
src/cmd/8l/pass.c
src/cmd/ld/dwarf.c
src/cmd/ld/dwarf_defs.h

index 22f266fe4c793d18917b4139bfb0c8a589f05e36..b8f47fc00f66ef8974af7bd5bbaf7f60c420b7d0 100644 (file)
@@ -95,6 +95,7 @@ struct        Prog
        Prog*   dlink;
        Prog*   pcond;  /* work on this */
        vlong   pc;
+       int32   spadj;
        int32   line;
        short   as;
        char    ft;     /* oclass cache */
@@ -102,7 +103,7 @@ struct      Prog
        uchar   mark;   /* work on these */
        uchar   back;
 
-       char    width;          /* fake for DATA */
+       char    width;  /* fake for DATA */
        char    mode;   /* 16, 32, or 64 */
 };
 struct Auto
@@ -397,7 +398,7 @@ void        buildop(void);
 void   cflush(void);
 void   ckoff(Sym*, int32);
 Prog*  copyp(Prog*);
-vlong   cpos(void);
+vlong  cpos(void);
 double cputime(void);
 void   datblk(int32, int32);
 void   deadcode(void);
@@ -463,3 +464,9 @@ uint32      machheadr(void);
 #pragma        varargck        type    "R"     int
 #pragma        varargck        type    "A"     int
 #pragma        varargck        argpos  diag 1
+
+/* Used by ../ld/dwarf.c */
+enum
+{
+       DWARFREGSP = 7
+};
index ea3351239f7c6e021d3f82601bf489d27f27f1dc..d207e748320cffc59a83ecb8b0aa8190361c23b2 100644 (file)
@@ -692,7 +692,7 @@ dostkoff(void)
                                        p->from.type = D_INDIR+D_GS;
                                p->from.offset = tlsoffset+0;
                                p->to.type = D_CX;
-                               
+
                                if(debug['K']) {
                                        // 6l -K means check not only for stack
                                        // overflow but stack underflow.
@@ -843,6 +843,7 @@ dostkoff(void)
                                p->as = AADJSP;
                                p->from.type = D_CONST;
                                p->from.offset = autoffset;
+                               p->spadj = autoffset;
                                if(q != P)
                                        q->pcond = p;
                        }
@@ -903,26 +904,32 @@ dostkoff(void)
                case APUSHL:
                case APUSHFL:
                        deltasp += 4;
+                       p->spadj = 4;
                        continue;
                case APUSHQ:
                case APUSHFQ:
                        deltasp += 8;
+                       p->spadj = 8;
                        continue;
                case APUSHW:
                case APUSHFW:
                        deltasp += 2;
+                       p->spadj = 2;
                        continue;
                case APOPL:
                case APOPFL:
                        deltasp -= 4;
+                       p->spadj = -4;
                        continue;
                case APOPQ:
                case APOPFQ:
                        deltasp -= 8;
+                       p->spadj = -8;
                        continue;
                case APOPW:
                case APOPFW:
                        deltasp -= 2;
+                       p->spadj = -2;
                        continue;
                case ARET:
                        break;
@@ -937,7 +944,7 @@ dostkoff(void)
                        p->as = AADJSP;
                        p->from.type = D_CONST;
                        p->from.offset = -autoffset;
-
+                       p->spadj = -autoffset;
                        p = appendp(p);
                        p->as = ARET;
                }
@@ -954,6 +961,7 @@ dostkoff(void)
                q->from = zprg.from;
                q->from.type = D_CONST;
                q->from.offset = -autoffset;
+               q->spadj = -autoffset;
                q->to = zprg.to;
                continue;
        }
index e3b53f202fba98875d625982f51ce681791fdeec..489f1ae8cbf84cabb442017c8452c2fd767d187c 100644 (file)
@@ -95,6 +95,7 @@ struct        Prog
        Prog*   dlink;
        Prog*   pcond;  /* work on this */
        int32   pc;
+       int32   spadj;
        int32   line;
        short   as;
        char    width;          /* fake for DATA */
@@ -346,7 +347,7 @@ Prog*       brloop(Prog*);
 void   cflush(void);
 void   ckoff(Sym*, int32);
 Prog*  copyp(Prog*);
-vlong   cpos(void);
+vlong  cpos(void);
 double cputime(void);
 void   datblk(int32, int32, int32);
 void   diag(char*, ...);
@@ -412,3 +413,9 @@ void        deadcode(void);
 #pragma        varargck        type    "P"     Prog*
 #pragma        varargck        type    "R"     int
 #pragma        varargck        type    "A"     int
+
+/* Used by ../ld/dwarf.c */
+enum
+{
+       DWARFREGSP = 4
+};
index bf09fd9111614abfbbcf7c3d4b5ec5a4ae8e4ce2..f59ccdb61e5bd3199dbe416dfdc970edd745df93 100644 (file)
@@ -392,10 +392,10 @@ patch(void)
        for(p = firstp; p != P; p = p->link) {
                if(HEADTYPE == 10) {    // Windows
                        // Convert
-                       //   op   n(GS), reg
+                       //   op   n(GS), reg
                        // to
                        //   MOVL 0x2C(FS), reg
-                       //   op   n(reg), reg
+                       //   op   n(reg), reg
                        // The purpose of this patch is to fix some accesses
                        // to extern register variables (TLS) on Windows, as
                        // a different method is used to access them.
@@ -770,6 +770,7 @@ dostkoff(void)
                                p->as = AADJSP;
                                p->from.type = D_CONST;
                                p->from.offset = autoffset;
+                               p->spadj = autoffset;
                                if(q != P)
                                        q->pcond = p;
                        }
@@ -792,18 +793,22 @@ dostkoff(void)
                case APUSHL:
                case APUSHFL:
                        deltasp += 4;
+                       p->spadj = 4;
                        continue;
                case APUSHW:
                case APUSHFW:
                        deltasp += 2;
+                       p->spadj = 2;
                        continue;
                case APOPL:
                case APOPFL:
                        deltasp -= 4;
+                       p->spadj = -4;
                        continue;
                case APOPW:
                case APOPFW:
                        deltasp -= 2;
+                       p->spadj = -2;
                        continue;
                case ARET:
                        break;
@@ -822,6 +827,7 @@ dostkoff(void)
                        q->as = AADJSP;
                        q->from.type = D_CONST;
                        q->from.offset = -autoffset;
+                       p->spadj = -autoffset;
                }
                continue;
 
@@ -836,6 +842,7 @@ dostkoff(void)
                q->from = zprg.from;
                q->from.type = D_CONST;
                q->from.offset = -autoffset;
+               p->spadj = -autoffset;
                q->to = zprg.to;
                continue;
        }
index add9277b369eab43e48975a0dc5ae2430b5e3854..6e440d0465c94dcdec07d1d0a7750d7aa51c4cb0 100644 (file)
@@ -10,7 +10,7 @@
 #include       "../ld/macho.h"
 
 /*
- * Offsets and sizes of the .debug_* sections in the cout file.
+ * Offsets and sizes of the debug_* sections in the cout file.
  */
 
 static vlong abbrevo;
@@ -19,7 +19,78 @@ static vlong lineo;
 static vlong linesize;
 static vlong infoo;
 static vlong infosize;
+static vlong frameo;
+static vlong framesize;
 
+/*
+ *  Basic I/O
+ */
+
+static void
+addrput(vlong addr)
+{
+       switch(PtrSize) {
+       case 4:
+               LPUT(addr);
+               break;
+       case 8:
+               VPUT(addr);
+               break;
+       }
+}
+
+
+static int
+uleb128enc(uvlong v, char* dst)
+{
+       uint8 c, len;
+
+       len = 0;
+       do {
+               c = v & 0x7f;
+               v >>= 7;
+               if (v)
+                       c |= 0x80;
+               if (dst)
+                       *dst++ = c;
+               len++;
+       } while (c & 0x80);
+       return len;
+};
+
+
+static int
+sleb128enc(vlong v, char *dst)
+{
+       uint8 c, s, len;
+
+       len = 0;
+       do {
+               c = v & 0x7f;
+               s = v & 0x40;
+               v >>= 7;
+               if ((v != -1 || !s) && (v != 0 || s))
+                       c |= 0x80;
+               if (dst)
+                       *dst++ = c;
+               len++;
+       } while(c & 0x80);
+       return len;
+}
+
+static void
+uleb128put(vlong v)
+{
+       char buf[10];
+       strnput(buf, uleb128enc(v, buf));
+}
+
+static void
+sleb128put(vlong v)
+{
+       char buf[10];
+       strnput(buf, sleb128enc(v, buf));
+}
 
 /*
  * Defining Abbrevs.  This is hardcoded, and there will be
@@ -72,13 +143,34 @@ struct DWAbbrev {
        },
 };
 
+static void
+writeabbrev(void)
+{
+       int i, n;
+
+       abbrevo = cpos();
+       for (i = 1; i < DW_NABRV; i++) {
+               // See section 7.5.3
+               uleb128put(i);
+               uleb128put(abbrevs[i].tag);
+               cput(abbrevs[i].children);
+               // 0 is not a valid attr or form, so we can treat this as
+               // a string
+               n = strlen((char*)abbrevs[i].attr) / 2;
+               strnput((char*)abbrevs[i].attr,
+                       (n+1) * sizeof(DWAttrForm));
+       }
+       cput(0);
+       abbrevsize = cpos() - abbrevo;
+}
+
 /*
  * Debugging Information Entries and their attributes
  */
 
-
-// for string and block, value contains the length, and data the data,
-// for all others, value is the whole thing and data is null.
+// For DW_CLS_string and _block, value should contain the length, and
+// data the data, for all others, value is the whole thing and data is
+// null.
 
 typedef struct DWAttr DWAttr;
 struct DWAttr {
@@ -126,46 +218,6 @@ newattr(DWDie *die, uint8 attr, int cls, vlong value, char *data)
        return a;
 }
 
-static void addrput(vlong addr)
-{
-       switch(PtrSize) {
-       case 4:
-               LPUT(addr);
-               break;
-       case 8:
-               VPUT(addr);
-               break;
-       }
-}
-
-static void
-uleb128put(uvlong v)
-{
-       uint8 c;
-
-       do {
-               c = v & 0x7f;
-               v >>= 7;
-               if (v) c |= 0x80;
-               cput(c);
-       } while (c & 0x80);
-};
-
-static void
-sleb128put(vlong v)
-{
-       uint8 c, s;
-
-       do {
-               c = v & 0x7f;
-               s = c & 0x40;
-               v >>= 7;
-               if ((v != -1 || !s) && (v != 0 || s))
-                       c |= 0x80;
-               cput(c);
-       } while(c & 0x80);
-};
-
 static void
 putattr(int form, int cls, vlong value, char *data)
 {
@@ -209,11 +261,11 @@ putattr(int form, int cls, vlong value, char *data)
                WPUT(value);
                break;
 
-       case DW_FORM_data4:     // constant, lineptr, loclistptr, macptr, rangelistptr
+       case DW_FORM_data4:     // constant, {line,loclist,mac,rangelist}ptr
                LPUT(value);
                break;
 
-       case DW_FORM_data8:     // constant, lineptr, loclistptr, macptr, rangelistptr
+       case DW_FORM_data8:     // constant, {line,loclist,mac,rangelist}ptr
                VPUT(value);
                break;
 
@@ -542,28 +594,6 @@ searchhist(vlong absline)
        return lh;
 }
 
-static void
-writeabbrev(void)
-{
-       int i, n;
-
-       abbrevo = cpos();
-       for (i = 1; i < DW_NABRV; i++) {
-               // See section 7.5.3
-               uleb128put(i);
-               uleb128put(abbrevs[i].tag);
-               cput(abbrevs[i].children);
-               // 0 is not a valid attr or form, so we can treat this as
-               // a string
-               n = strlen((char *) abbrevs[i].attr) / 2;
-               strnput((char *) abbrevs[i].attr,
-                       (n + 1) * sizeof(DWAttrForm));
-       }
-       cput(0);
-       abbrevsize = cpos() - abbrevo;
-}
-
-
 static int
 guesslang(char *s)
 {
@@ -596,8 +626,8 @@ putpclcdelta(vlong delta_pc, vlong delta_lc)
        }
 
        if (delta_pc) {
-         cput(DW_LNS_advance_pc);
-         sleb128put(delta_pc);
+               cput(DW_LNS_advance_pc);
+               sleb128put(delta_pc);
        }
 
        cput(DW_LNS_advance_line);
@@ -616,8 +646,8 @@ flushunit(vlong pc, vlong unitstart)
 {
        vlong here;
 
-       if (dwinfo != 0 && pc != 0) {
-               newattr(dwinfo, DW_AT_high_pc, DW_CLS_ADDRESS, pc, 0);
+       if (dwinfo != nil && pc != 0) {
+               newattr(dwinfo, DW_AT_high_pc, DW_CLS_ADDRESS, pc+1, 0);
        }
 
        if (unitstart >= 0) {
@@ -641,19 +671,22 @@ writelines(void)
        Sym *s;
        char *unitname;
        vlong unitstart;
-       vlong pc, lc, llc, lline;
+       vlong pc, epc, lc, llc, lline;
        int currfile;
        int i;
        Linehist *lh;
 
+       q = nil;
        unitstart = -1;
-       pc = 0;
+       epc = pc = 0;
        lc = 1;
        llc = 1;
        currfile = -1;
        lineo = cpos();
 
        for (p = textp; p != P; p = p->pcond) {
+               curtext = p; // for diag
+
                s = p->from.sym;
                if (s == nil || s->type != STEXT) {
                        diag("->pcond was supposed to loop over STEXT: %P", p);
@@ -663,7 +696,7 @@ writelines(void)
                // Look for history stack.  If we find one,
                // we're entering a new compilation unit
                if ((unitname = inithist(p->to.autom)) != 0) {
-                       flushunit(pc, unitstart);
+                       flushunit(epc, unitstart);
                        unitstart = cpos();
                        if(debug['v'] > 1) {
                                print("dwarf writelines found %s\n", unitname);
@@ -675,8 +708,8 @@ writelines(void)
                        dwinfo = newdie(dwinfo, DW_ABRV_COMPUNIT);
                        newattr(dwinfo, DW_AT_name, DW_CLS_STRING, strlen(unitname), unitname);
                        newattr(dwinfo, DW_AT_language, DW_CLS_CONSTANT, guesslang(unitname), 0);
-                       newattr(dwinfo, DW_AT_stmt_list,  DW_CLS_PTR, unitstart - lineo, 0);
-                       newattr(dwinfo, DW_AT_low_pc,  DW_CLS_ADDRESS, p->pc, 0);
+                       newattr(dwinfo, DW_AT_stmt_list, DW_CLS_PTR, unitstart - lineo, 0);
+                       newattr(dwinfo, DW_AT_low_pc, DW_CLS_ADDRESS, p->pc, 0);
                        // Write .debug_line Line Number Program Header (sec 6.2.4)
                        // Fields marked with (*) must be changed for 64-bit dwarf
                        LPUT(0);   // unit_length (*), will be filled in later.
@@ -701,7 +734,7 @@ writelines(void)
                                // 4 zeros: the string termination + 3 fields.
                        }
 
-                       pc = p->pc;
+                       epc = pc = p->pc;
                        currfile = 1;
                        lc = 1;
                        llc = 1;
@@ -711,7 +744,7 @@ writelines(void)
                        cput(DW_LNE_set_address);
                        addrput(pc);
                }
-               if (!p->from.sym->reachable)
+               if (!s->reachable)
                        continue;
                if (unitstart < 0) {
                        diag("reachable code before seeing any history: %P", p);
@@ -721,11 +754,9 @@ writelines(void)
                dwinfo->child = newdie(dwinfo->child, DW_ABRV_FUNCTION);
                newattr(dwinfo->child, DW_AT_name, DW_CLS_STRING, strlen(s->name), s->name);
                newattr(dwinfo->child, DW_AT_low_pc, DW_CLS_ADDRESS, p->pc, 0);
-               if (debug['v'] > 1)
-                 print("frame offset: %d\n", p->to.offset);
-//             newattr(dwinfo->child, DW_AT_return_addr,  DW_CLS_BLOCK, p->to.offset, 0);
 
                for(q = p; q != P && (q == p || q->as != ATEXT); q = q->link) {
+                        epc = q->pc;
                        lh = searchhist(q->line);
                        if (lh == nil) {
                                diag("corrupt history or bad absolute line: %P", q);
@@ -734,7 +765,7 @@ writelines(void)
                        lline = lh->line + q->line - lh->absline;
                        if (debug['v'] > 1)
                                print("%6llux %s[%lld] %P\n", q->pc, histfile[lh->file], lline, q);
-                       // Only emit a line program statement if line has changed.
+
                        if (q->line == lc)
                                continue;
                        if (currfile != lh->file) {
@@ -747,12 +778,130 @@ writelines(void)
                        lc  = q->line;
                        llc = lline;
                }
-               newattr(dwinfo->child, DW_AT_high_pc, DW_CLS_ADDRESS, pc, 0);
+
+               newattr(dwinfo->child, DW_AT_high_pc, DW_CLS_ADDRESS, epc+1, 0);
+
        }
-       flushunit(pc, unitstart);
+
+       flushunit(epc, unitstart);
        linesize = cpos() - lineo;
 }
 
+/*
+ *  Emit .debug_frame
+ */
+enum
+{
+       CIERESERVE = 16,
+       DATAALIGNMENTFACTOR = -4,
+       FAKERETURNCOLUMN = 16
+};
+
+static void
+putpccfadelta(vlong deltapc, vlong cfa)
+{
+       if (deltapc < 0x40) {
+               cput(DW_CFA_advance_loc + deltapc);
+       } else if (deltapc < 0x100) {
+               cput(DW_CFA_advance_loc1);
+               cput(deltapc);
+       } else if (deltapc < 0x10000) {
+               cput(DW_CFA_advance_loc2);
+               WPUT(deltapc);
+       } else {
+               cput(DW_CFA_advance_loc4);
+               LPUT(deltapc);
+       }
+
+       cput(DW_CFA_def_cfa_offset_sf);
+       sleb128put(cfa / DATAALIGNMENTFACTOR);
+}
+
+static void
+writeframes(void)
+{
+       Prog *p, *q;
+       Sym *s;
+       vlong fdeo, fdesize, pad, cfa, pc, epc;
+
+       frameo = cpos();
+
+       // Emit the CIE, Section 6.4.1
+       LPUT(CIERESERVE);  // initial length, must be multiple of PtrSize
+       LPUT(0xffffffff);  // cid.
+       cput(3);        // dwarf version
+       cput(0);        // augmentation ""
+       uleb128put(1);  // code_alignment_factor
+       sleb128put(DATAALIGNMENTFACTOR); // guess
+       uleb128put(FAKERETURNCOLUMN); // return_address_register
+
+       cput(DW_CFA_def_cfa);
+       uleb128put(DWARFREGSP); // register SP (**ABI-dependent, defined in l.h)
+       uleb128put(PtrSize);    // offset
+
+       cput(DW_CFA_offset + FAKERETURNCOLUMN);  // return address
+       uleb128put(-PtrSize / DATAALIGNMENTFACTOR);     // at cfa - x*4
+
+       // 4 is to exclude the length field.
+       pad = CIERESERVE + frameo + 4 - cpos();
+       if (pad < 0) {
+               diag("CIERESERVE too small by %lld bytes.", -pad);
+               errorexit();
+       }
+       strnput("", pad);
+
+       for (p = textp; p != P; p = p->pcond) {
+               curtext = p; // for diag
+               s = p->from.sym;
+               if (s == nil || s->type != STEXT) {
+                       diag("->pcond was supposed to loop over STEXT: %P", p);
+                       continue;
+               }
+               if (!s->reachable)
+                       continue;
+
+               fdeo = cpos();
+               // Emit a FDE, Section 6.4.1, starting wit a placeholder.
+               LPUT(0);        // length, must be multiple of PtrSize
+               LPUT(0);        // Pointer to the CIE above, at offset 0
+               addrput(0);     // initial location
+               addrput(0);     // address range
+
+               cfa = PtrSize;  // CFA starts at sp+PtrSize
+               pc = p->pc;
+               epc = p->pc;
+
+               for(q = p; q != P && (q == p || q->as != ATEXT); q = q->link) {
+                       epc = q->pc;
+                       if (q->spadj == 0)
+                               continue;
+
+                       cfa += q->spadj;
+                       putpccfadelta(q->pc - pc, cfa);
+                       pc = q->pc;
+               }
+
+               fdesize = cpos() - fdeo - 4;    // exclude the length field.
+               pad = rnd(fdesize, PtrSize) - fdesize;
+               strnput("", pad);
+               fdesize += pad;
+               cflush();
+
+               // Emit the FDE header for real, Section 6.4.1.
+               seek(cout, fdeo, 0);
+               LPUT(fdesize);
+               LPUT(0);
+               addrput(p->pc);
+               addrput(epc - p->pc);
+
+               cflush();
+               seek(cout, fdeo + 4 + fdesize, 0);
+       }
+
+       cflush();
+       framesize = cpos() - frameo;
+}
+
 /*
  *  Walk DWarfDebugInfoEntries, and emit .debug_info
  */
@@ -790,8 +939,17 @@ writeinfo(void)
        infosize = cpos() - infoo;
 }
 
+void
+dwarfemitdebugsections(void)
+{
+       writeabbrev();
+       writelines();
+       writeframes();
+       writeinfo();
+}
+
 /*
- *  Elf sections.
+ *  Elf.
  */
 enum
 {
@@ -827,14 +985,6 @@ dwarfaddshstrings(Sym *shstrtab)
        elfstrdbg[ElfStrDebugStr]      = addstring(shstrtab, ".debug_str");
 }
 
-void
-dwarfemitdebugsections(void)
-{
-       writeabbrev();
-       writelines();
-       writeinfo();
-}
-
 void
 dwarfaddelfheaders(void)
 {
@@ -852,6 +1002,12 @@ dwarfaddelfheaders(void)
        sh->size = linesize;
        sh->addralign = 1;
 
+       sh = newElfShdr(elfstrdbg[ElfStrDebugFrame]);
+       sh->type = SHT_PROGBITS;
+       sh->off = frameo;
+       sh->size = framesize;
+       sh->addralign = 1;
+
        sh = newElfShdr(elfstrdbg[ElfStrDebugInfo]);
        sh->type = SHT_PROGBITS;
        sh->off = infoo;
@@ -859,6 +1015,9 @@ dwarfaddelfheaders(void)
        sh->addralign = 1;
 }
 
+/*
+ * Macho
+ */
 void
 dwarfaddmachoheaders(void)
 {
@@ -873,7 +1032,7 @@ dwarfaddmachoheaders(void)
 
        ms = newMachoSeg("__DWARF", 3);
        ms->fileoffset = fakestart;
-       ms->filesize = abbrevo-fakestart + abbrevsize+linesize+infosize;
+       ms->filesize = abbrevo-fakestart + abbrevsize+linesize+framesize+infosize;
 
        msect = newMachoSect(ms, "__debug_abbrev");
        msect->off = abbrevo;
@@ -883,6 +1042,10 @@ dwarfaddmachoheaders(void)
        msect->off = lineo;
        msect->size = linesize;
 
+       msect = newMachoSect(ms, "__debug_frame");
+       msect->off = frameo;
+       msect->size = framesize;
+
        msect = newMachoSect(ms, "__debug_info");
        msect->off = infoo;
        msect->size = infosize;
index 7bff4fbee8d0ab458dbf2649ab220cce2c7b5f41..3b54f77b0b596e50395c65be48ab5f109d2e5d45 100644 (file)
@@ -452,3 +452,39 @@ enum
        DW_MACINFO_end_file = 0x04,
        DW_MACINFO_vendor_ext = 0xff,
 };
+
+// Table 40.
+enum
+{                                      // operand,...
+       DW_CFA_nop = 0x00,
+       DW_CFA_set_loc = 0x01,          // address
+       DW_CFA_advance_loc1 = 0x02,     // 1-byte delta
+       DW_CFA_advance_loc2 = 0x03,     // 2-byte delta
+       DW_CFA_advance_loc4 = 0x04,     // 4-byte delta
+       DW_CFA_offset_extended = 0x05,  // ULEB128 register, ULEB128 offset
+       DW_CFA_restore_extended = 0x06, // ULEB128 register
+       DW_CFA_undefined = 0x07,        // ULEB128 register
+       DW_CFA_same_value = 0x08,       // ULEB128 register
+       DW_CFA_register = 0x09,         // ULEB128 register, ULEB128 register
+       DW_CFA_remember_state = 0x0a,
+       DW_CFA_restore_state = 0x0b,
+       DW_CFA_def_cfa = 0x0c,          // ULEB128 register, ULEB128 offset
+       DW_CFA_def_cfa_register = 0x0d, // ULEB128 register
+       DW_CFA_def_cfa_offset = 0x0e,   // ULEB128 offset
+       DW_CFA_def_cfa_expression = 0x0f, // BLOCK
+       DW_CFA_expression = 0x10,       // ULEB128 register, BLOCK
+       DW_CFA_offset_extended_sf = 0x11, // ULEB128 register, SLEB128 offset
+       DW_CFA_def_cfa_sf = 0x12,       // ULEB128 register, SLEB128 offset
+       DW_CFA_def_cfa_offset_sf = 0x13, // SLEB128 offset
+       DW_CFA_val_offset = 0x14,       // ULEB128, ULEB128
+       DW_CFA_val_offset_sf = 0x15,    // ULEB128, SLEB128
+       DW_CFA_val_expression = 0x16,   // ULEB128, BLOCK
+
+       DW_CFA_lo_user = 0x1c,
+       DW_CFA_hi_user = 0x3f,
+
+       // Opcodes that take an addend operand.
+       DW_CFA_advance_loc = 0x1<<6, // +delta
+       DW_CFA_offset      = 0x2<<6, // +register (ULEB128 offset)
+       DW_CFA_restore     = 0x3<<6, // +register
+};