view scan.c @ 16:a2a81589380d default tip

Reformat the whole source via clang-format for better consistency.
author Matti Hamalainen <ccr@tnsp.org>
date Thu, 14 Oct 2021 01:53:20 +0300
parents 84c0facfc43c
children
line wrap: on
line source

/*\
 *  dxa -- symbolic 65xx disassembler
 *
 *  Copyright (C) 1993, 1994 Marko M\"akel\"a
 *  Copyright (C) 2019 Cameron Kaiser
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
\*/

#define _SCAN_C_
#include "opcodes.h"
#include "options.h"
#include "proto.h"
#include <stdio.h>

int ScanSure(ADDR_T scanstart)
{
    ADDR_T address, addr;
    opcodes *instr;

    unsigned int size, counter;
    if (fVerbose)
        fprintf(stderr, "\n%s: scanning sure section $%04x", prog, scanstart);

    for (address = scanstart;; address += size)
    {
        if (GetMemFlag(address)) /* rest of routine not valid */
            return ((Options & M_DATA_BLOCKS) == O_DBL_STRICT);

        instr = &opset[Memory[address]];

        if (!instr->mnemonic) /* invalid opcode */
            return ((Options & M_DATA_BLOCKS) == O_DBL_STRICT);

        size = sizes[instr->admode];
        if ((ADDR_T)(address + size - StartAddress) > (ADDR_T)(EndAddress - StartAddress))
            break; /* end of program code encountered */

        switch (GetMemType(address))
        {
        case MEM_INSTRUCTION:
            return 0; /* The rest of the routine has already been processed. */

        case MEM_DATA:
            AddEntry(address, scanstart, WRN_INSTR_WRITTEN_TO);
            break;

        case MEM_PARAMETER:
            AddEntry(address, scanstart, WRN_PARAM_JUMPED_TO);
        }

        SetMemType(address, MEM_INSTRUCTION);

        for (counter = size, addr = address + 1; --counter; addr++)
            switch
                GetMemType(addr)
                {
                case MEM_INSTRUCTION:
                    AddEntry(addr, scanstart, WRN_PARAM_JUMPED_TO);
                    break;
                case MEM_DATA:
                    AddEntry(addr, scanstart, WRN_PARAM_WRITTEN_TO);
                    /* fall through */
                default:
                    SetMemType(addr, MEM_PARAMETER);
                }

        if (instr->admode == zrel)
        {
            addr = Memory[(ADDR_T)(address + 1)];

            if (GetMemFlag(addr) && GetMemType(addr) == MEM_UNPROCESSED)
                return (Options & M_DATA_BLOCKS) == O_DBL_STRICT;

            if (((ADDR_T)(addr - StartAddress) < (ADDR_T)(EndAddress - StartAddress) || Options & B_LBL_ALWAYS))
            {

                PutLabel(addr);
                PutReference(addr);
                PutLowByte(addr);
                PutHighByte(addr);
            }

            addr = (ADDR_T)((int)(char)Memory[(ADDR_T)(address + 2)] + address + size);
            goto IsJump;
        }

        if (instr->admode == rel)
        {
            addr = (ADDR_T)((int)(char)Memory[(ADDR_T)(address + 1)] + address + size);

            goto IsJump;
        }
        if ((instr->mnemonic == S_JSR || instr->mnemonic == S_JMP) && instr->admode == abso)
        {
            addr = Memory[(ADDR_T)(address + 1)] + (Memory[(ADDR_T)(address + 2)] << 8);

        IsJump:
            if (GetMemFlag(addr))
                return ((Options & M_DATA_BLOCKS) == O_DBL_STRICT);

            if ((ADDR_T)(addr - StartAddress) < (ADDR_T)(EndAddress - StartAddress))
            {
                if (GetMemType(addr) == MEM_INSTRUCTION)
                {
                    PutLabel(addr);
                    PutReference(addr);
                    PutLowByte(addr);
                    PutHighByte(addr);
                }
                else
                    AddEntry(addr, scanstart,
                             Options & B_SCEPTIC && instr->admode == rel && instr->mnemonic != S_BRA ? RTN_POTENTIAL
                                                                                                     : RTN_SURE);
            }
            else if (Options & B_LBL_ALWAYS)
            {
                PutLabel(addr);
                PutReference(addr);
                PutLowByte(addr);
                PutHighByte(addr);
            }

            if ((Options & M_DATA_BLOCKS) == O_DBL_STRICT && Options & B_JMP_STRICT && addr == address &&
                instr->mnemonic != S_BVC)
                return 1;
        }

        switch (instr->mnemonic)
        {
        case S_JMP:
            addr = Memory[(ADDR_T)(address + 1)] + (Memory[(ADDR_T)(address + 2)] << 8);

            if (instr->admode == iabs && (ADDR_T)(addr - StartAddress) < (ADDR_T)(EndAddress - StartAddress))
            {
                PutLabel(addr);
                PutReference(addr);
                PutLowByte(addr);
                PutHighByte(addr);

                /* Mark pointer as data. */
                switch (GetMemType(addr))
                {
                case MEM_UNPROCESSED:
                    SetMemType(addr, MEM_DATA);
                    break;
                case MEM_INSTRUCTION:
                    AddEntry(addr, scanstart, WRN_INSTR_WRITTEN_TO);
                    break;
                case MEM_PARAMETER:
                    AddEntry(addr, scanstart, WRN_PARAM_WRITTEN_TO);
                    break;
                }

                addr++;

                if ((ADDR_T)(addr - StartAddress) < (ADDR_T)(EndAddress - StartAddress))
                    switch (GetMemType(addr))
                    {
                    case MEM_UNPROCESSED:
                        SetMemType(addr, MEM_DATA);
                        break;
                    case MEM_INSTRUCTION:
                        AddEntry(addr, scanstart, WRN_INSTR_WRITTEN_TO);
                        break;
                    case MEM_PARAMETER:
                        AddEntry(addr, scanstart, WRN_PARAM_WRITTEN_TO);
                        break;
                    }
            }
            else if (Options & B_LBL_ALWAYS)
            {
                PutLabel(addr);
                PutReference(addr);
                PutLowByte(addr);
                PutHighByte(addr);
            }
            return 0;

        case S_BRA:
        case S_RTS:
        case S_RTI:
            return 0;

        case S_BRK:
        case S_STP:
            return (Options & M_DATA_BLOCKS) == O_DBL_STRICT && Options & B_BRK_REJECT;
        }

        if (instr->admode == rel)
        {
            if ((ADDR_T)(addr - scanstart) >= (ADDR_T)(address - scanstart) || GetMemType(addr) != MEM_INSTRUCTION)
            {
                if (GetMemType(address + size) != MEM_INSTRUCTION)
                    AddEntry(address + size, scanstart, RTN_POTENTIAL);

                return 0;
            }

            continue;
        }

        if (instr->mnemonic == S_JSR)
        {
            if (!(Options & B_STK_BALANCE))
            {
                if (GetMemType(address + size) != MEM_INSTRUCTION)
                    AddEntry(address + size, scanstart, RTN_POTENTIAL);

                return 0;
            }

            continue;
        }

        switch (size)
        {
        case 2:
            addr = Memory[(ADDR_T)(address + 1)];
            break;
        case 3:
            addr = Memory[(ADDR_T)(address + 1)] + (Memory[(ADDR_T)(address + 2)] << 8);
            break;
        }

        if (types[instr->admode] != impimm && GetMemFlag(addr) && GetMemType(addr) == MEM_UNPROCESSED)
            return (Options & M_DATA_BLOCKS) == O_DBL_STRICT;

        if (types[instr->admode] != impimm &&
            ((ADDR_T)(addr - StartAddress) < (ADDR_T)(EndAddress - StartAddress) || Options & B_LBL_ALWAYS))
        {
            PutLabel(addr);
            PutReference(addr);
            PutLowByte(addr);
            PutHighByte(addr);
        }

        if (types[instr->admode] != other && types[instr->admode] != impimm)
        {
            if ((ADDR_T)(addr - StartAddress) < (ADDR_T)(EndAddress - StartAddress))
            {
                switch (GetMemType(addr))
                {
                case MEM_UNPROCESSED:
                    SetMemType(addr, MEM_DATA);
                    break;
                case MEM_INSTRUCTION:
                    AddEntry(addr, scanstart, WRN_INSTR_WRITTEN_TO);
                    break;
                case MEM_PARAMETER:
                    AddEntry(addr, scanstart, WRN_PARAM_WRITTEN_TO);
                    break;
                }

                if (types[instr->admode] == absindir)
                {           /* indirect mode */
                    addr++; /* set flags for upper vector byte */

                    if ((ADDR_T)(addr - StartAddress) < (ADDR_T)(EndAddress - StartAddress))
                        switch (GetMemType(addr))
                        {
                        case MEM_UNPROCESSED:
                            SetMemType(addr, MEM_DATA);
                            break;
                        case MEM_INSTRUCTION:
                            AddEntry(addr, scanstart, WRN_INSTR_WRITTEN_TO);
                            break;
                        case MEM_PARAMETER:
                            AddEntry(addr, scanstart, WRN_PARAM_WRITTEN_TO);
                            break;
                        }
                }
            }
        }
    }

    /* end of program (unexpectedly) encountered */

    if (Options & O_DBL_STRICT)
        return 1;

    AddEntry(EndAddress, scanstart, WRN_RTN_TRUNCATED);
    return 0;
}

int ScanPotential(ADDR_T scanstart)
{
    ADDR_T address, addr;
    opcodes *instr;

    unsigned int size, counter;

    for (address = scanstart;; address += size)
    {
        if (GetMemFlag(address)) /* rest of routine not valid */
            return 1;

        instr = &opset[Memory[address]];

        if (!instr->mnemonic)
        { /* invalid opcode */
            SetMemFlag(address);

            if (GetMemType(address) == MEM_UNPROCESSED)
                SetMemType(address, MEM_DATA);
            return 1;
        }

        size = sizes[instr->admode];
        if ((ADDR_T)(address + size - StartAddress) > (ADDR_T)(EndAddress - StartAddress))
            break; /* end of program code encountered */

        if (GetMemType(address) == MEM_INSTRUCTION)
            return 0; /* The rest of the routine has already been processed. */

        if (instr->admode == zrel)
        {
            addr = Memory[(ADDR_T)(address + 1)];

            if (GetMemFlag(addr) && GetMemType(addr) == MEM_UNPROCESSED)
                goto Failure;

            if (((ADDR_T)(addr - StartAddress) < (ADDR_T)(EndAddress - StartAddress) || Options & B_LBL_ALWAYS))
                AddEntry(addr, scanstart, WRN_I_LABEL_NEEDED | WRN_B_TEMPORARY);

            addr = (ADDR_T)((int)(char)Memory[(ADDR_T)(address + 1)] + address + size);

            goto IsJump;
        }

        if (instr->admode == rel)
        {
            addr = (ADDR_T)((int)(char)Memory[(ADDR_T)(address + 1)] + address + size);

            goto IsJump;
        }

        switch (size)
        {
        case 2:
            addr = Memory[(ADDR_T)(address + 1)];
            break;
        case 3:
            addr = Memory[(ADDR_T)(address + 1)] + (Memory[(ADDR_T)(address + 2)] << 8);
            break;
        default:
            addr = address;
        }

        if (types[instr->admode] != impimm && GetMemFlag(addr) && GetMemType(addr) == MEM_UNPROCESSED)
        {
        Failure:
            SetMemFlag(address);

            if (GetMemType(address) == MEM_UNPROCESSED)
                SetMemType(address, MEM_DATA);
            return 1;
        }

        if ((instr->mnemonic == S_JSR || instr->mnemonic == S_JMP) && instr->admode == abso)
        {
        IsJump:
            if (GetMemFlag(addr))
            {
                SetMemFlag(address);

                if (GetMemType(address) == MEM_UNPROCESSED)
                    SetMemType(address, MEM_DATA);
                return 1;
            }

            if ((ADDR_T)(addr - StartAddress) < (ADDR_T)(EndAddress - StartAddress))
                AddEntry(addr, scanstart,
                         Options & B_SCEPTIC && instr->admode == rel && instr->mnemonic != S_BRA ? RTN_SUSP_POT
                                                                                                 : RTN_SUSPECTED);
            else if (Options & B_LBL_ALWAYS)
                AddEntry(addr, scanstart, WRN_I_LABEL_NEEDED | WRN_B_TEMPORARY);

            if (Options & B_JMP_STRICT && addr == address && instr->mnemonic != S_BVC)
            {
                SetMemFlag(address);

                if (GetMemType(address) == MEM_UNPROCESSED)
                    SetMemType(address, MEM_DATA);
                return 1;
            }
        }

        switch (instr->mnemonic)
        {
        case S_BRK:
        case S_STP:
            if (Options & B_BRK_REJECT)
            {
                SetMemFlag(address);

                if (GetMemType(address) == MEM_UNPROCESSED)
                    SetMemType(address, MEM_DATA);
                return 1;
            }
        }

        if (!GetMemFlag(address))
            switch (GetMemType(address))
            {
            case MEM_DATA:
                AddEntry(address, scanstart, WRN_INSTR_WRITTEN_TO | WRN_B_TEMPORARY);
                break;

            case MEM_PARAMETER:
                AddEntry(address, scanstart, WRN_PARAM_JUMPED_TO | WRN_B_TEMPORARY);
            }

        SetMemType(address, MEM_INSTRUCTION);

        for (counter = size, addr = address + 1; --counter; addr++)
            switch (GetMemType(addr))
            {
            case MEM_INSTRUCTION:
                AddEntry(addr, scanstart, WRN_PARAM_JUMPED_TO | WRN_B_TEMPORARY);
                break;
            case MEM_DATA:
                if (!GetMemFlag(addr))
                    AddEntry(addr, scanstart, WRN_PARAM_WRITTEN_TO | WRN_B_TEMPORARY);
                break;
            default:
                SetMemType(addr, MEM_PARAMETER);
            }

        switch (instr->mnemonic)
        {
        case S_BRK:
        case S_STP:
        case S_RTS:
        case S_BRA:
        case S_RTI:
            return 0;

        case S_JMP:
            addr = Memory[(ADDR_T)(address + 1)] + (Memory[(ADDR_T)(address + 2)] << 8);

            if (instr->admode == iabs && (ADDR_T)(addr - StartAddress) < (ADDR_T)(EndAddress - StartAddress))
            {
                AddEntry(addr, scanstart, WRN_I_LABEL_NEEDED | WRN_B_TEMPORARY);

                /* Mark pointer as data. */
                switch (GetMemType(addr))
                {
                case MEM_UNPROCESSED:
                    AddEntry(addr, scanstart, WRN_I_ACCESSED | WRN_B_TEMPORARY);
                    break;
                case MEM_INSTRUCTION:
                    AddEntry(addr, scanstart, WRN_INSTR_WRITTEN_TO | WRN_B_TEMPORARY);
                    break;
                case MEM_PARAMETER:
                    AddEntry(addr, scanstart, WRN_PARAM_WRITTEN_TO | WRN_B_TEMPORARY);
                    break;
                }

                addr++;

                if ((ADDR_T)(addr - StartAddress) < (ADDR_T)(EndAddress - StartAddress))
                    switch (GetMemType(addr))
                    {
                    case MEM_UNPROCESSED:
                        AddEntry(addr, scanstart, WRN_I_ACCESSED | WRN_B_TEMPORARY);
                        break;
                    case MEM_INSTRUCTION:
                        AddEntry(addr, scanstart, WRN_INSTR_WRITTEN_TO | WRN_B_TEMPORARY);
                        break;
                    case MEM_PARAMETER:
                        AddEntry(addr, scanstart, WRN_PARAM_WRITTEN_TO | WRN_B_TEMPORARY);
                        break;
                    }
            }
            else if (Options & B_LBL_ALWAYS)
                AddEntry(addr, scanstart, WRN_I_LABEL_NEEDED | WRN_B_TEMPORARY);

            return 0;
        }

        if (instr->admode == rel && GetMemType(address + size) != MEM_INSTRUCTION)
        {
            AddEntry(address + size, scanstart, RTN_SUSP_POT);

            return 0;
        }

        if (instr->mnemonic == S_JSR)
        {
            if (!(Options & B_STK_BALANCE))
            {
                if (GetMemType(address + size) != MEM_INSTRUCTION)
                    AddEntry(address + size, scanstart, RTN_SUSP_POT);

                return 0;
            }

            continue;
        }

        switch (size)
        {
        case 2:
            addr = Memory[(ADDR_T)(address + 1)];
            break;
        case 3:
            addr = Memory[(ADDR_T)(address + 1)] + (Memory[(ADDR_T)(address + 2)] << 8);
            break;
        }

        if (types[instr->admode] != impimm &&
            ((ADDR_T)(addr - StartAddress) < (ADDR_T)(EndAddress - StartAddress) || Options & B_LBL_ALWAYS))
            AddEntry(addr, scanstart, WRN_I_LABEL_NEEDED | WRN_B_TEMPORARY);

        if (types[instr->admode] != other && types[instr->admode] != impimm)
        {
            if ((ADDR_T)(addr - StartAddress) < (ADDR_T)(EndAddress - StartAddress))
            {
                switch (GetMemType(addr))
                {
                case MEM_UNPROCESSED:
                    AddEntry(addr, scanstart, WRN_I_ACCESSED | WRN_B_TEMPORARY);
                    break;
                case MEM_INSTRUCTION:
                    AddEntry(addr, scanstart, WRN_INSTR_WRITTEN_TO | WRN_B_TEMPORARY);
                    break;
                case MEM_PARAMETER:
                    AddEntry(addr, scanstart, WRN_PARAM_WRITTEN_TO | WRN_B_TEMPORARY);
                    break;
                }

                if (types[instr->admode] == absindir)
                {           /* indirect mode */
                    addr++; /* set flags for upper vector byte */

                    if ((ADDR_T)(addr - StartAddress) < (ADDR_T)(EndAddress - StartAddress))
                        switch (GetMemType(addr))
                        {
                        case MEM_UNPROCESSED:
                            AddEntry(addr, scanstart, WRN_I_ACCESSED | WRN_B_TEMPORARY);
                            break;
                        case MEM_INSTRUCTION:
                            AddEntry(addr, scanstart, WRN_INSTR_WRITTEN_TO | WRN_B_TEMPORARY);
                            break;
                        case MEM_PARAMETER:
                            AddEntry(addr, scanstart, WRN_PARAM_WRITTEN_TO | WRN_B_TEMPORARY);
                            break;
                        }
                }
            }
        }
    }

    /* end of program (unexpectedly) encountered */

    return 1;
}

int ScanSpecified(void)
{
    table *entry;

    if (fVerbose)
        fprintf(stderr, "%s: scanning the routines at specified address(es)", prog);

    while ((entry = FindNextEntryType(NULL, ~0, RTN_SURE)))
    {
        PutLabel(entry->address);
        PutReference(entry->address);
        PutLowByte(entry->address);
        PutHighByte(entry->address);

        if (ScanSure(entry->address))
        {
            fprintf(stderr, "For routine specified at %i:", (unsigned int)entry->address);
            return 1;
        }
        entry = FindNextEntryType(NULL, ~0, RTN_SURE); // valgrind fart
        DeleteEntry(entry);
    }

    return 0;
}

void UnDoScan(ADDR_T scanstart)
{
    opcodes *instr;
    unsigned counter;
    ADDR_T address;

    for (address = scanstart; address != EndAddress; address++)
    {
        if (GetMemFlag(address))
            return;

        switch (GetMemType(address))
        {
        case MEM_UNPROCESSED:
            return;

        case MEM_INSTRUCTION:
            SetMemFlag(address);
            SetMemType(address, MEM_DATA); /* This could cause WRN_PARAM_WRITTEN_TO
                          in vain. */
            instr = &opset[Memory[address++]];
            for (counter = sizes[instr->admode]; --counter; address++)
                if (GetMemType(address) == MEM_PARAMETER)
                    SetMemType(address, MEM_UNPROCESSED);
                else if (GetMemType(address) == MEM_INSTRUCTION)
                    break;

            if (instr->mnemonic == S_STP || instr->mnemonic == S_BRK || instr->mnemonic == S_RTI ||
                instr->mnemonic == S_RTS || instr->mnemonic == S_JMP || instr->admode == rel)
                return;

            address--;
            break;

        case MEM_PARAMETER:
            SetMemType(address, MEM_UNPROCESSED);
        }
    }
}

void DeleteSuspectedParents(ADDR_T child)
{
    table *entry = NULL;

    while ((entry = FindNextEntry(entry, child, ~(RTN_B_PROCESSED | RTN_B_TEMPORARY), RTN_SUSPECTED)))
    {
        if (entry->type & RTN_B_PROCESSED && entry->parent != child)
            DeleteSuspectedParents(entry->parent);

        DeleteEntry(entry);
    }

    entry = NULL;

    while ((entry = FindNextEntryTypeParent(entry, child, ~0, RTN_SUSP_POT)))
        DeleteEntry(entry);

    entry = NULL;

    while ((entry = FindNextEntryTypeParent(entry, child, MASK_ANY | WRN_B_TEMPORARY, WRN_ANY | WRN_B_TEMPORARY)))
    {
        if (entry->type == (WRN_PARAM_JUMPED_TO | WRN_B_TEMPORARY))
            SetMemType(entry->address, MEM_PARAMETER);

        DeleteEntry(entry);
    }

    UnDoScan(child);
}

void ScanPotentials(void)
{
    table *entry;
    ADDR_T address;

    if (fVerbose)
        fprintf(stderr, "\n%s: scanning potential routines\n", prog);

    while ((entry = FindNextEntryType(NULL, ~0, RTN_POTENTIAL)))
    {
        address = entry->address;
        DeleteEntry(entry);

        if (!ScanPotential(address))
        {
            while ((entry = FindNextEntryType(NULL, ~RTN_B_TEMPORARY, RTN_SUSPECTED)))
            {
                entry->type |= RTN_B_PROCESSED;

                if (ScanPotential(entry->address) && (Options & M_DATA_BLOCKS) != O_DBL_IGNORE)
                {
                    DeleteSuspectedParents(entry->address);
                    SetMemType(address, MEM_DATA);
                }
            }

            if (GetMemType(address) != MEM_DATA)
            {
                PutLabel(address);
                PutLowByte(address);
                PutHighByte(address);
            }

            entry = NULL;

            while ((entry = FindNextEntryType(entry, ~0, RTN_B_TEMPORARY | RTN_SUSPECTED | RTN_B_PROCESSED)))
                DeleteEntry(entry);

            entry = NULL;

            while ((entry = FindNextEntryType(entry, ~0, RTN_SUSPECTED | RTN_B_PROCESSED)))
            {
                PutLabel(entry->address);
                PutReference(entry->address);
                PutLowByte(entry->address);
                PutHighByte(entry->address);
                DeleteEntry(entry);
            }

            entry = NULL;

            while ((entry = FindNextEntryType(entry, ~0, RTN_SUSP_POT)))
                entry->type = RTN_POTENTIAL;

            entry = NULL;

            while ((entry = FindNextEntryType(entry, MASK_ANY | WRN_B_TEMPORARY, WRN_ANY | WRN_B_TEMPORARY)))
            {
                switch (entry->type & ~WRN_B_TEMPORARY)
                {
                case WRN_PARAM_WRITTEN_TO:
                    if (GetMemType(entry->address) == MEM_DATA)
                        SetMemType(entry->address, MEM_PARAMETER);
                    entry->type &= ~WRN_B_TEMPORARY;
                    break;

                case WRN_INSTR_WRITTEN_TO:
                    if (GetMemType(entry->address) == MEM_DATA)
                        SetMemType(entry->address, MEM_INSTRUCTION);
                    entry->type &= ~WRN_B_TEMPORARY;
                    break;

                case WRN_I_ACCESSED:
                    SetMemType(entry->address, MEM_DATA);
                    /* fall through */
                case WRN_I_LABEL_NEEDED:
                    PutLabel(entry->address);
                    PutReference(entry->address);
                    PutLowByte(entry->address);
                    PutHighByte(entry->address);
                    DeleteEntry(entry);
                    break;

                default:
                    entry->type &= ~WRN_B_TEMPORARY;
                }
            }
        }
        else
        {
            DeleteSuspectedParents(address);
            SetMemType(address, MEM_DATA);
        }
    }
}

void ScanTheRest(void)
{
    ADDR_T address;
    table *entry;
    unsigned int fPotentials;

    if ((Options & M_DATA_BLOCKS) == O_DBL_NOSCAN)
    {
        for (address = StartAddress; address != EndAddress; address++)
            if (GetMemType(address) == MEM_UNPROCESSED)
                SetMemType(address, MEM_DATA);

        return;
    }

    if (fVerbose)
        fprintf(stderr, "%s: scanning the remaining bytes for routines\n", prog);

    for (address = StartAddress; address != EndAddress; address++)
    {
        if (GetMemType(address) || GetMemFlag(address))
            continue; /* scan only unprocessed bytes */

        if (Options & B_RSC_STRICT)
            switch (opset[Memory[address]].mnemonic)
            {
            case S_RTI:
            case S_RTS:
            case S_BRK:
            case S_STP:
                continue;

            case S_BRA:
                break;

            default:
                if (opset[Memory[address]].admode == rel && GetMemType(address + sizes[rel]) != MEM_INSTRUCTION)
                    AddEntry(address + sizes[rel], address, RTN_SUSPECTED | RTN_B_TEMPORARY);
            }

        if (fVerbose)
            fprintf(stderr, "\n%s: scanning at $%04x", prog, address);

        if (!ScanPotential(address))
        {
            while ((entry = FindNextEntryType(NULL, ~RTN_B_TEMPORARY, RTN_SUSPECTED)))
            {
                entry->type |= RTN_B_PROCESSED;

                if (ScanPotential(entry->address) && (Options & M_DATA_BLOCKS) != O_DBL_IGNORE)
                {
                    DeleteSuspectedParents(entry->address);
                    SetMemType(address, MEM_DATA);
                }
            }

            if (GetMemType(address) != MEM_DATA)
            {
                PutLabel(address);
                PutReference(address);
                PutLowByte(address);
                PutHighByte(address);
            }

            fPotentials = FALSE;
            entry = NULL;

            while ((entry = FindNextEntryType(entry, ~0, RTN_SUSP_POT)))
            {
                fPotentials = TRUE;
                entry->type = RTN_POTENTIAL;
            }

            entry = NULL;

            while ((entry = FindNextEntryType(entry, ~0, RTN_B_TEMPORARY | RTN_SUSPECTED | RTN_B_PROCESSED)))
                DeleteEntry(entry);

            entry = NULL;

            while ((entry = FindNextEntryType(entry, ~0, RTN_SUSPECTED | RTN_B_PROCESSED)))
            {
                PutLabel(entry->address);
                PutReference(entry->address);
                PutLowByte(entry->address);
                PutHighByte(entry->address);
                DeleteEntry(entry);
            }

            entry = NULL;

            while ((entry = FindNextEntryType(entry, MASK_ANY | WRN_B_TEMPORARY, WRN_ANY | WRN_B_TEMPORARY)))
            {
                switch (entry->type & ~WRN_B_TEMPORARY)
                {
                case WRN_PARAM_WRITTEN_TO:
                    if (GetMemType(entry->address) == MEM_DATA)
                        SetMemType(entry->address, MEM_PARAMETER);
                    entry->type &= ~WRN_B_TEMPORARY;
                    break;

                case WRN_INSTR_WRITTEN_TO:
                    if (GetMemType(entry->address) == MEM_DATA)
                        SetMemType(entry->address, MEM_INSTRUCTION);
                    entry->type &= ~WRN_B_TEMPORARY;
                    break;

                case WRN_I_ACCESSED:
                    SetMemType(entry->address, MEM_DATA);
                    /* fall through */
                case WRN_I_LABEL_NEEDED:
                    PutLabel(entry->address);
                    PutReference(entry->address);
                    PutLowByte(entry->address);
                    PutHighByte(entry->address);
                    DeleteEntry(entry);
                    break;

                default:
                    entry->type &= ~WRN_B_TEMPORARY;
                }
            }

            if (fPotentials)
                ScanPotentials();
        }
        else
        {
            DeleteSuspectedParents(address);
            SetMemType(address, MEM_DATA);
        }
    }

    if (fVerbose)
        fprintf(stderr, "\n");

    for (address = StartAddress; address != EndAddress; address++)
        if (GetMemType(address) == MEM_UNPROCESSED)
        {
            fPotentials = GetMemFlag(address) ? MEM_PARAMETER : MEM_DATA;
            SetMemType(address, fPotentials);
        }
}