#drinc:util.g
#dis.g
#funcs.g

/*
 * data.d - routines to dump data and bss hunks.
 *
 * May/June 1989, by Chris Gray
 */

/*
 * skipData - skip past some data in a pass one of a text hunk. This is
 *	done specially to make it fast, since the prepasses can be numerous.
 */

proc skipData(register *Hunk_t h; *ulong pOffset, pBase;
	      register ulong length)void:
    register ulong offset, base;
    register *DefList_t dfl;
    register *RelocEntry_t rle @ dfl;
    register *byte ptr;

    offset := pOffset*;
    base := pBase*;
    ptr := h*.h_bytes;
    ptr := ptr + offset;
    while
	if offset >= length then
	    false
	else
	    dfl := h*.h_lastLabel;
	    while dfl ~= nil and dfl*.dfl_offset < offset do
		dfl := dfl*.dfl_next;
	    od;
	    if dfl ~= nil and dfl*.dfl_offset = offset then
		h*.h_lastLabel := dfl*.dfl_next;
		false
	    else
		h*.h_lastLabel := dfl;
		if h*.h_labelsOK and
		    (h*.h_branchMap + offset / 8)* & (1 << (offset % 8)) ~= 0
		then
		    false
		else
		    rle := h*.h_lastReloc;
		    while rle*.rle_offset < offset do
			rle := rle + sizeof(RelocEntry_t);
		    od;
		    h*.h_lastReloc := rle;
		    if rle*.rle_offset = offset and
			rle*.rle_u.rle_hunk ~= nil and
			not rle*.rle_isRef and h*.h_labelsOK and
			rle*.rle_u.rle_hunk*.hkl_hunkNumber = h*.h_hunkNumber
		    then
			labelAt1(h,
			    make((ptr + 0)*, ulong) << 24 |
			    make((ptr + 1)*, ulong) << 16 |
			    make((ptr + 2)*, ulong) <<	8 |
			    make((ptr + 3)*, ulong)
			);
			offset := offset + 3;
			ptr := ptr + 3;
		    fi;
		    true
		fi
	    fi
	fi
    do
	offset := offset + 1;
	ptr := ptr + 1;
    od;
    pOffset* := offset;
    pBase* := base;
corp;

/*
 * showData - symbolic output of a data hunk or data parts of a text hunk.
 */

proc showData(register *Hunk_t h; *ulong pOffset, pBase; ulong length;
	      bool stopOnLabel, updateBase, absoluteAddress)void:
    uint MAX_COLUMNS = 77 - 39;
    register *byte ptr;
    register *char label;
    register ulong offset, base, ul;
    ulong trueAddr, hunk;
    uint column;
    register byte b;
    register char c @ b;
    bool inString, first, wantStop, doneLabel;

    offset := pOffset*;
    base := pBase*;
    ptr := h*.h_bytes;
    ptr := ptr + offset;
    if offset ~= length then
	first := true;
	column := 0;
	inString := false;
	wantStop := false;
	while offset < length and not getInterrupted() and not wantStop do
	    doneLabel := false;
	    label := findLabel1(h, offset);
	    if label ~= nil then
		wantStop := stopOnLabel;
		if not first then
		    first := true;
		    if inString then
			inString := false;
			putChar1('\'');
		    fi;
		    newLine();
		fi;
		if updateBase then
		    base := offset;
		fi;
		doPosition(offset, base);
		message(label);
		/* because the findLabel code moves past the label when it
		   returns it, the code disassembler will not find the label
		   here again. This does not work for the generated label
		   case below, however, so it must avoid printing the label
		   if it is going to continue with code disassembly */
		newLine();
		column := 0;
	    elif h*.h_labelsOK and isLabel1(h, offset) then
		if isBranch1(h, offset) then
		    wantStop := stopOnLabel;
		fi;
		if not first then
		    first := true;
		    if inString then
			inString := false;
			putChar1('\'');
		    fi;
		    newLine();
		    column := 0;
		fi;
		if not wantStop then
		    doPosition(offset, base);
		    putChar1('L');
		    if absoluteAddress then
			putLongHex(offset);
			newLine();
			column := 0;
		    else
			putWordHex(offset - base);
			message("   ");
			doneLabel := true;
		    fi;
		fi;
	    fi;
	    ul := make((ptr + 0)*, ulong) << 24 |
		  make((ptr + 1)*, ulong) << 16 |
		  make((ptr + 2)*, ulong) <<  8 |
		  make((ptr + 3)*, ulong);
	    label := findReloc(h, ul, offset, &trueAddr, &hunk);
	    if label ~= nil then
		if not first then
		    first := true;
		    if inString then
			inString := false;
			putChar1('\'');
		    fi;
		    newLine();
		fi;
	    fi;
	    if first and not wantStop then
		if not doneLabel then
		    doPosition(offset, base);
		    message("        ");
		fi;
		message("dc.");
	    fi;
	    if label ~= nil then
		message("l       ");
		ptr := ptr + 4;
		offset := offset + 4;
		if hunk = h*.h_hunkNumber and trueAddr ~= ul and h*.h_labelsOK
		then
		    putChar1('L');
		    if absoluteAddress then
			putLongHex(ul);
		    else
			putWordHex(ul - base);
		    fi;
		    labelAt1(h, ul);
		else
		    message(label);
		    if trueAddr ~= ul then
			message("+0x");
			ul := ul - trueAddr;
			if ul > 0xffff then
			    putLongHex(ul);
			else
			    putWordHex(ul);
			fi;
		    fi;
		fi;
		newLine();
		column := 0;
	    elif not wantStop then
		if first then
		    message("b       ");
		fi;
		b := ptr*;
		ptr := ptr + 1;
		offset := offset + 1;
		if c >= ' ' and c <= '~' then
		    if inString or first then
			if first then
			    first := false;
			    putChar1('\'');
			    column := column + 1;
			fi;
			inString := true;
			if c = '\'' then
			    message("\'\'");
			    column := column + 2;
			else
			    putChar1(c);
			    column := column + 1;
			fi;
		    else
			if not first then
			    first := true;
			    newLine();
			    column := 0;
			fi;
			ptr := ptr - 1;
			offset := offset - 1;
		    fi;
		else
		    if inString and not first then
			inString := false;
			ptr := ptr - 1;
			offset := offset - 1;
			message("\'\n");
			first := true;
			column := 0;
		    else
			if not first then
			    putChar1(',');
			    column := column + 1;
			fi;
			putLongDec(b);
			column := column + 1;
			if b > 9 then
			    column := column + 1;
			    if b > 99 then
				column := column + 1;
			    fi;
			fi;
			first := false;
		    fi;
		fi;
		if column > MAX_COLUMNS then
		    column := 0;
		    if inString then
			inString := false;
			putChar1('\'');
		    fi;
		    newLine();
		    first := true;
		fi;
	    fi;
	od;
	if not first then
	    if inString then
		putChar1('\'');
	    fi;
	    newLine();
	fi;
    fi;
    pOffset* := offset;
    pBase* := base;
corp;

/*
 * showBss - symbolic output of a bss hunk.
 */

proc showBss(*Hunk_t h)void:
    register *DefList_t dfl;
    register ulong offset;
    register *char prevName;

    newLine();
    offset := 0;
    dfl := h*.h_defList;
    if dfl*.dfl_offset ~= 0 then
	doPosition(offset, 0);
	message("        ds.b       ");
	putLongHex(dfl*.dfl_offset);
	newLine();
	offset := dfl*.dfl_offset;
    fi;
    while dfl ~= nil and not getInterrupted() do
	doPosition(offset, 0);
	prevName := dfl*.dfl_name;
	message(prevName);
	newLine();
	doPosition(offset, 0);
	message("        ds.b       ");
	dfl := dfl*.dfl_next;
	if dfl ~= nil then
	    if CharsEqual(dfl*.dfl_name, prevName) then
		dfl := dfl*.dfl_next;
	    fi;
	    if dfl ~= nil then
		putLongDec(dfl*.dfl_offset - offset);
		newLine();
		offset := dfl*.dfl_offset;
	    fi;
	fi;
    od;
    putLongDec(h*.h_bytesLength - offset);
    newLine();
corp;
