void parse() throws MemoryAccessException {
		Address curr = address;
		Address limit = address.add(length);

		int exOpcodeOrParam;
		long operand1;
		int operand1Len;
		long operand2;
		int operand2Len;
		LEB128Info uleb128;

		while (curr.compareTo(limit) < 0) {

			StringBuilder sb = new StringBuilder();
			Address instrAddr = curr;

			int opbyte = GccAnalysisUtils.readByte(program, curr) & WHOLE_BYTE_MASK;

			int opcode = (opbyte & HIGH_2_BITS_MASK);

			exOpcodeOrParam = (opbyte & LOW_6_BITS_MASK);
			boolean primaryOpcode = opcode != 0;

			curr = curr.add(1);

			if (primaryOpcode) {
				switch (opcode) {

					case DW_CFA_advance_loc:
						primaryOpcode = true;

						sb.append("DW_CFA_advance_loc delta[" + exOpcodeOrParam + "]");
						break;
					case DW_CFA_offset:
						primaryOpcode = true;

						uleb128 = GccAnalysisUtils.readULEB128Info(program, curr);
						operand1 = uleb128.asLong();
						operand1Len = uleb128.getLength();

						curr = curr.add(operand1Len);

						sb.append("DW_CFA_offset reg[" + exOpcodeOrParam + "] " + operand1);
						break;
					case DW_CFA_restore:
						primaryOpcode = true;
						sb.append("DW_CFA_restore reg[" + exOpcodeOrParam + "]");
						break;
				}
			}
			else {
				switch (exOpcodeOrParam) {

					//  case DW_CFA_extended:
					case DW_CFA_nop:
						primaryOpcode = true;
						sb.append("DW_CFA_nop");
						break;

					case DW_CFA_set_loc:

						// NOTE: This may actually be a LE128-encoded value..
						operand1 = GccAnalysisUtils.readDWord(program, curr) & 0xFFFFFFFF;
						curr = curr.add(4);

						sb.append("DW_CFA_set_loc addr[" + operand1 + "]");
						break;

					case DW_CFA_advance_loc1:
						operand1 = GccAnalysisUtils.readByte(program, curr) & 0xFF;
						curr = curr.add(1);

						sb.append("DW_CFA_advance_loc1 delta[" + operand1 + "]");
						break;

					case DW_CFA_advance_loc2:
						operand1 = GccAnalysisUtils.readWord(program, curr) & 0xFFFF;
						curr = curr.add(2);

						sb.append("DW_CFA_advance_loc2 delta[" + operand1 + "]");
						break;

					case DW_CFA_advance_loc4:
						operand1 = GccAnalysisUtils.readDWord(program, curr) & 0xFFFFFFFF;
						curr = curr.add(4);

						sb.append("DW_CFA_advance_loc4 delta[" + operand1 + "]");
						break;

					case DW_CFA_offset_extended:
						uleb128 = GccAnalysisUtils.readULEB128Info(program, curr);
						operand1 = uleb128.asLong();
						operand1Len = uleb128.getLength();
						curr = curr.add(operand1Len);

						uleb128 = GccAnalysisUtils.readULEB128Info(program, curr);
						operand2 = uleb128.asLong();
						operand2Len = uleb128.getLength();
						curr = curr.add(operand2Len);

						sb.append(
							"DW_CFA_offset_extended reg[" + operand1 + "] reg[" + operand2 + "]");
						break;

					case DW_CFA_restore_extended:
						uleb128 = GccAnalysisUtils.readULEB128Info(program, curr);
						operand1 = uleb128.asLong();
						operand1Len = uleb128.getLength();
						curr = curr.add(operand1Len);

						sb.append("DW_CFA_restore_extended reg[" + operand1 + "]");
						break;

					case DW_CFA_undefined:
						uleb128 = GccAnalysisUtils.readULEB128Info(program, curr);
						operand1 = uleb128.asLong();
						operand1Len = uleb128.getLength();
						curr = curr.add(operand1Len);

						sb.append("DW_CFA_undefined reg[" + operand1 + "]");
						break;

					case DW_CFA_same_value:
						uleb128 = GccAnalysisUtils.readULEB128Info(program, curr);
						operand1 = uleb128.asLong();
						operand1Len = uleb128.getLength();
						curr = curr.add(operand1Len);

						sb.append("DW_CFA_same_value reg[" + operand1 + "]");
						break;

					case DW_CFA_register:
						uleb128 = GccAnalysisUtils.readULEB128Info(program, curr);
						operand1 = uleb128.asLong();
						operand1Len = uleb128.getLength();
						curr = curr.add(operand1Len);

						uleb128 = GccAnalysisUtils.readULEB128Info(program, curr);
						operand2 = uleb128.asLong();
						operand2Len = uleb128.getLength();
						curr = curr.add(operand2Len);

						sb.append("DW_CFA_register reg[" + operand1 + "] reg[" + operand2 + "]");
						break;

					case DW_CFA_remember_state:
						sb.append("DW_CFA_remember_state");
						break;

					case DW_CFA_restore_state:
						sb.append("DW_CFA_restore_state");
						break;

					case DW_CFA_def_cfa:
						uleb128 = GccAnalysisUtils.readULEB128Info(program, curr);
						operand1 = uleb128.asLong();
						operand1Len = uleb128.getLength();
						curr = curr.add(operand1Len);

						uleb128 = GccAnalysisUtils.readULEB128Info(program, curr);
						operand2 = uleb128.asLong();
						operand2Len = uleb128.getLength();
						curr = curr.add(operand2Len);

						sb.append("DW_CFA_def_cfa reg[" + operand1 + "] offs[" + operand2 + "]");
						break;

					case DW_CFA_def_cfa_register:
						uleb128 = GccAnalysisUtils.readULEB128Info(program, curr);
						operand1 = uleb128.asLong();
						operand1Len = uleb128.getLength();
						curr = curr.add(operand1Len);

						sb.append("DW_CFA_def_cfa_register reg[" + operand1 + "]");
						break;

					case DW_CFA_def_cfa_offset:
						uleb128 = GccAnalysisUtils.readULEB128Info(program, curr);
						operand1 = uleb128.asLong();
						operand1Len = uleb128.getLength();
						curr = curr.add(operand1Len);

						sb.append("DW_CFA_def_cfa_offset offs[" + operand1 + "]");
						break;

					case DW_CFA_def_cfa_expression:
						sb.append("DW_CFA_def_cfa_expression BLOCK");
						break;

					case DW_CFA_expression:
						uleb128 = GccAnalysisUtils.readULEB128Info(program, curr);
						operand1 = uleb128.asLong();
						operand1Len = uleb128.getLength();
						curr = curr.add(operand1Len);

						sb.append("DW_CFA_expression reg[" + operand1 + "] BLOCK");
						break;

					case DW_CFA_offset_extended_sf:
						uleb128 = GccAnalysisUtils.readULEB128Info(program, curr);
						operand1 = uleb128.asLong();
						operand1Len = uleb128.getLength();
						curr = curr.add(operand1Len);

						uleb128 = GccAnalysisUtils.readULEB128Info(program, curr);
						operand2 = uleb128.asLong();
						operand2Len = uleb128.getLength();
						curr = curr.add(operand2Len);

						sb.append("DW_CFA_offset_extended_sf reg[" + operand1 + "] offs[" +
							operand2 + "]");
						break;

					case DW_CFA_def_cfa_sf:
						uleb128 = GccAnalysisUtils.readULEB128Info(program, curr);
						operand1 = uleb128.asLong();
						operand1Len = uleb128.getLength();
						curr = curr.add(operand1Len);

						uleb128 = GccAnalysisUtils.readULEB128Info(program, curr);
						operand2 = uleb128.asLong();
						operand2Len = uleb128.getLength();
						curr = curr.add(operand2Len);

						sb.append("DW_CFA_def_cfa_sf reg[" + operand1 + "] offs[" + operand2 + "]");
						break;

					case DW_CFA_def_cfa_offset_sf:
						uleb128 = GccAnalysisUtils.readULEB128Info(program, curr);
						operand1 = uleb128.asLong();
						operand1Len = uleb128.getLength();
						curr = curr.add(operand1Len);

						sb.append("DW_CFA_def_cfa_offset_sf offs[" + operand1 + "]");
						break;

					case DW_CFA_val_offset:
						uleb128 = GccAnalysisUtils.readULEB128Info(program, curr);
						operand1 = uleb128.asLong();
						operand1Len = uleb128.getLength();
						curr = curr.add(operand1Len);

						uleb128 = GccAnalysisUtils.readULEB128Info(program, curr);
						operand2 = uleb128.asLong();
						operand2Len = uleb128.getLength();
						curr = curr.add(operand2Len);

						sb.append("DW_CFA_val_offset [" + operand1 + "] [" + operand2 + "]");
						break;

					case DW_CFA_val_offset_sf:
						uleb128 = GccAnalysisUtils.readULEB128Info(program, curr);
						operand1 = uleb128.asLong();
						operand1Len = uleb128.getLength();
						curr = curr.add(operand1Len);

						uleb128 = GccAnalysisUtils.readULEB128Info(program, curr);
						operand2 = uleb128.asLong();
						operand2Len = uleb128.getLength();
						curr = curr.add(operand2Len);

						sb.append("DW_CFA_val_offset_sf [" + operand1 + "] [" + operand2 + "]");
						break;

					case DW_CFA_val_expression:
						uleb128 = GccAnalysisUtils.readULEB128Info(program, curr);
						operand1 = uleb128.asLong();
						operand1Len = uleb128.getLength();
						curr = curr.add(operand1Len);

						sb.append("DW_CFA_val_expression [" + operand1 + "] BLOCK");
						break;

					case DW_CFA_MIPS_advance_loc8:
						operand1 = GccAnalysisUtils.readQWord(program, curr) & 0xFFFF;
						curr = curr.add(8);

						sb.append("DW_CFA_MIPS_advance_loc8 + " + operand1);

						break;

					case DW_CFA_GNU_window_save:
						sb.append("DW_CFA_GNU_window_save");
						break;

					case DW_CFA_GNU_args_size:
						operand1 = GccAnalysisUtils.readByte(program, curr);
						curr = curr.add(1);
						sb.append("DW_CFA_GNU_args_size [" + operand1 + "]");
						break;

					case DW_CFA_lo_user:
						sb.append("DW_CFA_lo_user");
						break;

					case DW_CFA_hi_user:
						sb.append("DW_CFA_hi_user");
						break;

				}
			}

			SetCommentCmd.createComment(program, instrAddr, sb.toString(), CommentType.EOL);

			Msg.info(this, sb.toString());
		}
	}
Constructs an opcode parser.
@param program the program with the bytes to parse
@param address the address of the bytes to parse
@param length the number of bytes to parse
Ghidra/Features/Base/src/main/java/ghidra/app/plugin/exceptionhandlers/gcc/structures/ehFrame/DwarfCallFrameOpcodeParser.java