void WriteSignedLeb(MappedFileCursor cur, int i) { byte b; do { b = (byte)(i & 0x7F); i >>= 7; if ((i != 0 || (b & 0x40) != 0) && (i != -1 || (b & 0x40) == 0)) { b |= 0x80; } cur.WriteByte(b); } while ((b & 0x80) != 0); }
void WriteLeb(MappedFileCursor cur, int i) { byte b; do { b = (byte)(i & 0x7F); i >>= 7; if (i != 0) { b |= 0x80; } cur.WriteByte(b); } while (i != 0); }
void MakeLineProgram(MappedFileCursor cur, LineItem[] lines) { LineItem line; LineItem lineLast; int iLine; int iOpcode; int iConstAddPc; int iAddrDif; int iLineDif; bool fFixIt; iConstAddPc = (255 - m_lineHead.opcode_base) / m_lineHead.line_range; iLine = 0; fFixIt = false; for (; ;) { if (iLine >= lines.Length) { break; } lineLast.Address = 0; lineLast.File = 1; lineLast.Line = 1; lineLast.Column = 0; lineLast.Discr = 0; lineLast.IsStmt = m_lineHead.default_is_stmt != 0; for (; ;) { line = lines[iLine++]; if (line.IsStmt != lineLast.IsStmt) { cur.WriteByte((byte)StdLineOp.DW_LNS_negate_stmt); } if (line.Discr != lineLast.Discr) { cur.WriteByte((byte)StdLineOp.DW_LNS_extended_op); // count of following bytes depends on size of LEB128 byte cb = 2; uint val = (uint)line.Discr; while ((val >>= 7) != 0) { cb++; } cur.WriteByte(cb); cur.WriteByte((byte)ExtLineOp.DW_LNE_set_discriminator); WriteLeb(cur, line.Discr); } if (line.File != lineLast.File) { cur.WriteByte((byte)StdLineOp.DW_LNS_set_file); WriteLeb(cur, line.File); } if (line.Column != lineLast.Column) { cur.WriteByte((byte)StdLineOp.DW_LNS_set_column); WriteLeb(cur, line.Column); } iLineDif = line.Line - lineLast.Line; iAddrDif = (line.Address - lineLast.Address) / m_lineHead.minimum_instruction_length; if (iAddrDif < 0) { cur.WriteByte((byte)StdLineOp.DW_LNS_extended_op); cur.WriteByte(5); cur.WriteByte((byte)ExtLineOp.DW_LNE_set_address); cur.WriteUint((uint)line.Discr); iAddrDif = 0; } if (line.IsEnd) { if (iLineDif != 0) { cur.WriteByte((byte)StdLineOp.DW_LNS_advance_line); WriteSignedLeb(cur, iLineDif); } if (iAddrDif != 0) { cur.WriteByte((byte)StdLineOp.DW_LNS_advance_pc); WriteLeb(cur, iAddrDif); } cur.WriteByte((byte)StdLineOp.DW_LNS_extended_op); cur.WriteByte(1); // count of following bytes cur.WriteByte((byte)ExtLineOp.DW_LNE_end_sequence); break; } if (iLineDif < m_lineHead.line_base || iLineDif >= m_lineHead.line_base + m_lineHead.line_range) { // line dif exceeds range of special opcode cur.WriteByte((byte)StdLineOp.DW_LNS_advance_line); WriteSignedLeb(cur, iLineDif); iLineDif = 0; } FixOpcode: if (fFixIt || iAddrDif > iConstAddPc) { // address dif exceeds range of special opcode if (fFixIt || iAddrDif > iConstAddPc * 2) { // Big dif, use multi-byte opcode cur.WriteByte((byte)StdLineOp.DW_LNS_advance_pc); WriteLeb(cur, iAddrDif); iAddrDif = 0; } else { // Within range of single byte opcode cur.WriteByte((byte)StdLineOp.DW_LNS_const_add_pc); iAddrDif -= iConstAddPc; } fFixIt = false; } if (iAddrDif == 0 && iLineDif == 0) { cur.WriteByte((byte)StdLineOp.DW_LNS_copy); } else { // Compute special opcode iOpcode = iLineDif - m_lineHead.line_base + m_lineHead.line_range * iAddrDif + m_lineHead.opcode_base; if (iOpcode > 255) { fFixIt = true; goto FixOpcode; } cur.WriteByte((byte)iOpcode); } // Move on to next line if (iLine >= lines.Length) { throw new Exception("Line list did not end with End Sequence"); } lineLast = line; } } }