/* (C) 2003-2007 Willem Jan Hengeveld <itsme@xs4all.nl>
 * Web: http://www.xs4all.nl/~itsme/
 *      http://wiki.xda-developers.com/
 *
 * $Id$
 */
#include <util/wintypes.h>
#include "itsutils.h"
#include "dllversion.h"
#include "debug.h"
#include "args.h"
#include <stdio.h>
#include <string.h>
#include <util/rapitypes.h>

#include <string>
#include <map>
#include "stringutils.h"
#include "ptrutils.h"

//
//  default:
//     list the kernel address mappings
//     ( by calling SummarizePageTable and dumping 0x80000000-0xa0000000)
//  verbose ( -v )
//     list current process section
//     ( by calling SummarizePageTable and dumping 0x0-0xffffffff)
//
//  for one section ( -s 0x.... )
//     list virtual address ranges used by section
//     SummarizeSection(onlyvirtual=true)
//  verbose for one section ( -v -s 0x.... )
//     list virtual to physical address mapping used by section
//     SummarizeSection(onlyvirtual=false)
typedef std::map<HANDLE,CEPROCESSENTRY> ProcessInfoMap;

// todo: fix bug, where the last few pages of a section are not saved.
// todo: add option to save all sections to files.
// todo: add option to produce list of  v -> p, p, p ...
// todo: create tool to search sections for binary string.
//
// todo: create streaming interface to read memory, this should greatly improve processing speed.
//
// maybe add feature to save smaller sections, with max empty space 1M orso.
// todo: automatically figure out what area is the sdram.
//       ( by checking where virtual fffd0000 is mapped )
//
bool ITReadProcessMemory(HANDLE hProc, DWORD dwOffset, BYTE *buffer, DWORD dwBytesWanted, DWORD *pdwNumberOfBytesRead);
HANDLE ITGetProcessHandle(const std::string& szProcessName);

DWORD dwPhys_min= 0x00000000;
DWORD dwPhys_max= 0x00000000;
DWORD dwVirt_min= 0x00000000;
DWORD dwVirt_max= 0x00000000;

std::string g_savefilename;
FILE *g_f= NULL;
bool is_in_psave_range(DWORD dwPhys)
{
    return (dwPhys_min==dwPhys_max) || (dwPhys_min<=dwPhys && dwPhys<dwPhys_max);
}
bool is_in_vsave_range(DWORD dwVirt)
{
    return (dwVirt_min==dwVirt_max) || (dwVirt_min<=dwVirt && dwVirt<dwVirt_max);
}

bool save_to_section_file(DWORD dwStart, DWORD dwLength)
{
    if (g_savefilename.empty())
        return false;

    if (g_f==NULL) {
        g_f= fopen(g_savefilename.c_str(), "wb");
        if (g_f==NULL) {
            perror(stringformat("open %s", g_savefilename.c_str()).c_str());
            g_savefilename.clear();
            return false;
        }
    }

    while (dwLength) {
        DWORD dwWanted= dwLength;
        if (dwWanted>=0x8000)
            dwWanted= 0x8000;
        DWORD nRead;
        ByteVector data; data.resize(dwWanted);
        if (!ITReadProcessMemory(NULL, dwStart, vectorptr(data), data.size(), &nRead)) {
            debug("error reading section data at %08lx\n", dwStart);
            return false;
        }

        if (0!=fseek(g_f, dwStart & 0x1ffffff, SEEK_SET))
            perror(stringformat("seek %08lx %s", dwStart & 0x1ffffff, g_savefilename.c_str()).c_str());
        size_t n= fwrite(vectorptr(data), 1, data.size(), g_f);
        if (n!=data.size())
            perror(stringformat("writing %s", g_savefilename.c_str()).c_str());
        dwLength -= dwWanted;
        dwStart += dwWanted;
    }

    return true;
}

bool ITReadProcessMemory(HANDLE hProc, DWORD dwOffset, BYTE *buffer, DWORD dwBytesWanted, DWORD *pdwNumberOfBytesRead)
{
    ReadProcessMemoryParams inbuf;
    DWORD outsize=0;
    ReadProcessMemoryResult *outbuf=NULL;

    //debug("ITReadProcessMemory(%08lx %08lx %08lx)\n", hProc, dwOffset, dwBytesWanted);
    inbuf.hProcess= hProc;
    inbuf.dwOffset= dwOffset;
    inbuf.nSize= dwBytesWanted;
    inbuf.nDataAccess= 0;
    outbuf= NULL; outsize= 0;
    HRESULT res= ItsutilsInvoke("ITReadProcessMemory",
            sizeof(ReadProcessMemoryParams), (BYTE*)&inbuf,
            &outsize, (BYTE**)&outbuf);
    if (res || outbuf==NULL)
    {
        error(res, "ITReadProcessMemory");
        return false;
    }
    memcpy(buffer, &outbuf->buffer, outbuf->dwNumberOfBytesRead);
    *pdwNumberOfBytesRead= outbuf->dwNumberOfBytesRead;
    RapiFree(outbuf);

    return true;
}


// NOTE: we assume everything is read with the same handle in one session
typedef std::map<DWORD, ByteVector> OffsetBufferMap;
OffsetBufferMap cache;
bool BufferedReadMemory(HANDLE hProc, DWORD dwOffset, ByteVector **pbuf)
{
    //debug("BufferedReadMemory(%08lx)\n", dwOffset);
    OffsetBufferMap::iterator i= cache.find(dwOffset&~0xfff);
    if (i==cache.end()) {
        ByteVector bv;
        bv.resize(0x1000);
        DWORD nRead;
        if (!ITReadProcessMemory(hProc, dwOffset&~0xfff, vectorptr(bv), bv.size(), &nRead))
            return false;

        cache[dwOffset&~0xfff].swap(bv);
        i= cache.find(dwOffset&~0xfff);
    }
    //debug("setting final: %08lx  (size=%x)\n", (*i).first, (*i).second.size());
    *pbuf= &((*i).second);

    return true;
}

bool CachedITReadProcessMemory(HANDLE hProc, DWORD dwOffset, BYTE *buffer, DWORD dwBytesWanted, DWORD *pdwNumberOfBytesRead)
{
    //debug("CachedITReadProcessMemory(%08lx)\n", dwOffset);
    if ((dwOffset&~0xfff)!=((dwOffset+dwBytesWanted-1)&~0xfff))
        return ITReadProcessMemory(hProc, dwOffset, buffer, dwBytesWanted, pdwNumberOfBytesRead);
    ByteVector *pbv;
    if (!BufferedReadMemory(hProc, dwOffset, &pbv))
        return false;
    memcpy(buffer, vectorptr((*pbv))+(dwOffset&0xFFF), dwBytesWanted);
    return true;
}
HANDLE ITGetProcessHandle(const std::string& szProcessName)
{
    std::Wstring wprocname= ToWString(szProcessName);
    DWORD insize= (wprocname.size()+1)*sizeof(WCHAR);
    WCHAR *inbuf= (WCHAR*)RapiAlloc(insize);

    std::copy(wprocname.begin(), wprocname.end(), inbuf);
    inbuf[wprocname.size()]= 0;

    DWORD outsize=0;
    HANDLE *outbuf=NULL;

    HRESULT res= ItsutilsInvoke("ITGetProcessHandle",
            insize, (BYTE*)inbuf,
            &outsize, (BYTE**)&outbuf);
    if (res || outbuf==NULL) 
    {
        error(res, "ITGetProcessHandle");
        return INVALID_HANDLE_VALUE;
    }

    HANDLE hproc= *outbuf;

    RapiFree(outbuf);

    return hproc;
}
bool GetProcessInfo(bool bIncludeHeap, ProcessInfoMap &pinfo)
{
    GetProcessListParams p;
    p.bIncludeHeapUsage= bIncludeHeap;

    DWORD outsize=0;
    GetProcessListResult *outbuf=NULL;

    HRESULT res= ItsutilsInvoke("ITGetProcessList",
            sizeof(GetProcessListParams), (BYTE*)&p, &outsize, (BYTE**)&outbuf);

    if (res || outbuf==NULL)
    {
        error(res, "ITGetProcessList");
        return false;
    }
	if (outsize<PTR_DIFF(outbuf, outbuf->pe) 
			|| outsize < PTR_DIFF(outbuf, &outbuf->pe[outbuf->nEntries])) {
		debug("INTERNAL ERROR in itsutils.dll: expected %d bytes from ITGetProcessList, got %d\n",
			PTR_DIFF(outbuf, &outbuf->pe[outbuf->nEntries]), outsize);
		return false;
	}

    for (int i=0 ; i<outbuf->nEntries ; i++)
    {
        memcpy(&pinfo[(HANDLE)outbuf->pe[i].dwProcessID], &outbuf->pe[i], sizeof(CEPROCESSENTRY));
    }

    RapiFree(outbuf);
    
    return true;
}
DWORD ReadDword(DWORD dwOffset)
{
    DWORD nRead;
    DWORD dwValue;
    if (!CachedITReadProcessMemory(NULL, dwOffset, (BYTE*)&dwValue, sizeof(DWORD), &nRead))
        return 0;
    return dwValue;
}

DWORD FindVirtForPhys(const uint32_t *ptbl, DWORD dwPhys)
{
    DWORD dwAddr= 0;
    DWORD pidx= 0;
    do {
        DWORD pe= ptbl[pidx];

        if ((pe&3)==2) {
            if ((pe&0xfff00000)==(dwPhys&0xfff00000)) {
                return dwAddr | (dwPhys&0xfffff);
            }
        }

        dwAddr+=0x100000;
        pidx++;
    } while (dwAddr);
    return 0;
}
bool SummarizeTLB2(const uint32_t *ptbl1, DWORD dwVirtbase, DWORD dwTlbPhysAddr, DWORD pagesize, int nentries, bool bOnlyVirtual)
{
    DWORD ptbl2ofs= FindVirtForPhys(ptbl1, dwTlbPhysAddr);
    if (ptbl2ofs==NULL) {
        debug("ERROR: could not find virtual address for phys %08lx\n", dwTlbPhysAddr);
        return false;
    }
    DwordVector ptbl2; ptbl2.resize(nentries);
    DWORD nRead;
    if (!CachedITReadProcessMemory(NULL, ptbl2ofs, (BYTE*)vectorptr(ptbl2), ptbl2.size()*sizeof(DWORD), &nRead)) {
        debug("error reading tlb2 at %08lx\n", ptbl2ofs);
        return false;
    }

    bool bStarted= false;
    DWORD dwStartVirt= 0;
    DWORD dwStartPhys= 0;
    DWORD dwPrevPhys= 0;

    DWORD dwAddr= dwVirtbase;
    DWORD pidx= 0;
    for (int i=0 ; i<nentries ; i++)
    {
        DWORD pe= ptbl2[pidx];

        DWORD dwCurPhys= 0;
        bool bHasPhysAddr= false;
        bool bEndBlock= false;

        switch (pe&3) {
            case 0:  // ignore entry
                bEndBlock= true;
                break;
            case 1:  // large page descriptor
                dwCurPhys= pe&0xffff0000;
                bHasPhysAddr= true;
                break;
            case 2:  // small page descriptor
                dwCurPhys= pe&0xfffff000;
                bHasPhysAddr= true;
                break;
            case 3:  // tiny page descriptor
                dwCurPhys= pe&0xfffffc00;
                bHasPhysAddr= true;
                break;
        }
        if (!bOnlyVirtual&& dwCurPhys-dwPrevPhys!=pagesize)
            bEndBlock= true;

        if (bStarted && bEndBlock) {
            if (bOnlyVirtual)
                debug("v%08lx-%08lx  %8x\n", dwStartVirt, dwAddr, dwAddr-dwStartVirt);
            else
                debug("v%08lx-%08lx -> p%08lx-%08lx  %8x\n", dwStartVirt, dwAddr, dwStartPhys, dwPrevPhys+pagesize, dwAddr-dwStartVirt);
            bStarted= false;
        }
        if (bHasPhysAddr) {
            if (!bStarted) {
                bStarted= true;
                dwStartPhys= dwCurPhys;
                dwStartVirt= dwAddr;
            }
            dwPrevPhys= dwCurPhys;
        }

        dwAddr+=pagesize;
        pidx++;
    }
    if (bStarted) {
        if (bOnlyVirtual)
            debug("v%08lx-%08lx  %8x\n", dwStartVirt, dwAddr, dwAddr-dwStartVirt);
        else
            debug("v%08lx-%08lx -> p%08lx-%08lx  %8x\n", dwStartVirt, dwAddr, dwStartPhys, dwPrevPhys+pagesize, dwAddr-dwStartVirt);
        bStarted= false;
    }

    return true;
}
bool SummarizePageTable(bool bVerbose, bool bOnlyVirtual)
{
    DWORD ptbl1ofs= 0xfffd0000;
    DwordVector ptbl1; ptbl1.resize(4096);
    DWORD nRead;
    if (!ITReadProcessMemory(NULL, ptbl1ofs, (BYTE*)vectorptr(ptbl1), ptbl1.size()*sizeof(DWORD), &nRead)) {
        debug("error reading pagetable at %08lx\n", ptbl1ofs);
        return false;
    }

    DWORD pagesize= 0x100000;

    bool bStarted= false;
    DWORD dwStartVirt= 0;
    DWORD dwStartPhys= 0;
    DWORD dwPrevPhys= 0;

    DWORD dwAddr= bVerbose ? 0 : 0x80000000;
    DWORD pidx= dwAddr/pagesize;
    do {
        DWORD pe= ptbl1[pidx];

        DWORD dwCurPhys= 0;
        DWORD dwTlbPhys= 0;
        DWORD dwTlbPagesize= 0;
        bool bHasPhysAddr= false;
        bool bEndBlock= false;
        bool bHasTlb2= false;

        switch (pe&3) {
            case 0:  // ignore entry
                bEndBlock= true;
                break;
            case 1:  // coarse tlb entry
                dwTlbPhys= pe&0xfffffc00;
                dwTlbPagesize= 0x1000;
                bHasTlb2= true;
                bEndBlock= true;
                break;
            case 2:  // section descriptor
                dwCurPhys= pe&0xfff00000;
                bHasPhysAddr= true;
                break;
            case 3:  // fine tlb entry
                dwTlbPhys= pe&0xfffff000;
                dwTlbPagesize= 0x400;
                bHasTlb2= true;
                bEndBlock= true;
                break;
        }
        if (!bOnlyVirtual && dwCurPhys-dwPrevPhys!=pagesize)
            bEndBlock= true;

        if (bStarted && bEndBlock) {
            if (bOnlyVirtual)
                debug("v%08lx-%08lx  %8x\n", dwStartVirt, dwAddr, dwAddr-dwStartVirt);
            else
                debug("v%08lx-%08lx -> p%08lx-%08lx  %8x\n", dwStartVirt, dwAddr, dwStartPhys, dwPrevPhys+pagesize, dwAddr-dwStartVirt);
            bStarted= false;
        }
        if (bHasTlb2) {
            SummarizeTLB2(vectorptr(ptbl1), dwAddr, dwTlbPhys, dwTlbPagesize, pagesize/dwTlbPagesize, bOnlyVirtual);
        }
        if (bHasPhysAddr) {
            if (!bStarted) {
                bStarted= true;
                dwStartPhys= dwCurPhys;
                dwStartVirt= dwAddr;
            }
            dwPrevPhys= dwCurPhys;
        }

        dwAddr+=pagesize;
        pidx++;
        if (!bVerbose) {
            if (dwAddr==0xa0000000) {
                dwAddr= 0xe0000000;
                pidx += 0x40000000/pagesize;
            }
        }
    } while (dwAddr);
    if (bStarted) {
        if (bOnlyVirtual)
            debug("v%08lx-%08lx  %8x\n", dwStartVirt, dwAddr, dwAddr-dwStartVirt);
        else
            debug("v%08lx-%08lx -> p%08lx-%08lx  %8x\n", dwStartVirt, dwAddr, dwStartPhys, dwPrevPhys+pagesize, dwAddr-dwStartVirt);
        bStarted= false;
    }
    return true;
}

bool SummarizeSection(DWORD dwSectionAddr, bool bOnlyVirtual)
{
    DWORD sectionTableOfs= (dwSectionAddr<0x80000000) ? 0xFFFFC8A0 : 0xFFFFCB6C;
    //debug("sectiontable %08lx\n", sectionTableOfs);
    DwordVector SectionTable; SectionTable.resize((dwSectionAddr<0x80000000) ? 64 : 1);
    DWORD nRead;
    if (!CachedITReadProcessMemory(NULL, sectionTableOfs, (BYTE*)vectorptr(SectionTable), SectionTable.size()*sizeof(DWORD), &nRead)) {
        debug("error reading sectiontable at %08lx\n", sectionTableOfs);
        return false;
    }

    DWORD pagesize= 0x1000;

#define VA_BLOCK   16
#define VA_SECTION 25
#define VA_PAGE    12
#define BLOCK_MASK 0x1ff
#define PAGE_MASK  0x00f
#define NULL_BLOCK      0
#define RESERVED_BLOCK  1

    DWORD dwSectionOfs= SectionTable[(dwSectionAddr<0x80000000) ? dwSectionAddr>>VA_SECTION : 0];
    //debug("section %08lx\n", dwSectionOfs);
    DwordVector section; section.resize(512);
    if (!CachedITReadProcessMemory(NULL, dwSectionOfs, (BYTE*)vectorptr(section), section.size()*sizeof(DWORD), &nRead)) {
        debug("error reading section at %08lx\n", dwSectionOfs);
        return false;
    }

    DWORD dwStartPhys=0;
    DWORD dwStartVirt=0;
    DWORD dwPrevPhys=0;
    bool bStarted= false;
    DWORD dwVAddr= 0;
    for (DWORD ixBlock= 0 ; ixBlock<section.size() ; ixBlock++) {
        DWORD dwMemblockOfs = section[ixBlock];
        dwVAddr= dwSectionAddr+(ixBlock<<VA_BLOCK);

        if (dwMemblockOfs==NULL_BLOCK || dwMemblockOfs==RESERVED_BLOCK) {
            if (bStarted) {
                bool saved= false;
                if (!g_savefilename.empty() && is_in_psave_range(dwStartPhys) && is_in_vsave_range(dwStartVirt)) {
                    saved= save_to_section_file(dwStartVirt, dwVAddr-dwStartVirt);
                }

                if(bOnlyVirtual)
                    debug("v%08lx-%08lx%c %8x\n", dwStartVirt, dwVAddr, saved?'*':' ', dwVAddr-dwStartVirt);
                else
                    debug("v%08lx-%08lx%c-> p%08lx-%08lx  %8x\n", dwStartVirt, dwVAddr, saved?'*':' ', dwStartPhys, dwPrevPhys+pagesize, dwVAddr-dwStartVirt);
                bStarted= false;
            }
        }
        else {
            //debug("memblock %08lx\n", dwMemblockOfs);
            DwordVector memblock; memblock.resize(4);
            if (!CachedITReadProcessMemory(NULL, dwMemblockOfs, (BYTE*)vectorptr(memblock), memblock.size()*sizeof(DWORD), &nRead)) {
                debug("error reading memblock at %08lx\n", dwMemblockOfs);
                return false;
            }
            DWORD dwPagesOfs= memblock[3];
            //debug("pagelist %08lx\n", dwPagesOfs);
            DwordVector pages; pages.resize(16);
            if (!CachedITReadProcessMemory(NULL, dwPagesOfs, (BYTE*)vectorptr(pages), pages.size()*sizeof(DWORD), &nRead)) {
                debug("error reading memblock pagelist at %08lx\n", dwPagesOfs);
                return false;
            }

            for (DWORD ixPage= 0 ; ixPage<pages.size() ; ixPage++) {
                DWORD dwPageentry= pages[ixPage];
                if (dwPageentry==0xfffffff0 || dwPageentry==0 )  {
                    if (bStarted) {
                        bool saved= false;
                        if (!g_savefilename.empty() && is_in_psave_range(dwStartPhys) && is_in_vsave_range(dwStartVirt)) {
                            saved= save_to_section_file(dwStartVirt, dwVAddr-dwStartVirt);
                        }
                        if(bOnlyVirtual)
                            debug("v%08lx-%08lx%c %8x\n", dwStartVirt, dwVAddr, saved?'*':' ', dwVAddr-dwStartVirt);
                        else
                            debug("v%08lx-%08lx%c-> p%08lx-%08lx  %8x\n", dwStartVirt, dwVAddr, saved?'*':' ', dwStartPhys, dwPrevPhys+pagesize, dwVAddr-dwStartVirt);
                        bStarted= false;
                    }
                }
                else {
                    DWORD dwPhys= pages[ixPage]&0xfffff000;
                    if (!bOnlyVirtual && dwPhys-dwPrevPhys!=pagesize) {
                        if (bStarted) {
                            bool saved= false;
                            if (!g_savefilename.empty() && is_in_psave_range(dwStartPhys) && is_in_vsave_range(dwStartVirt)) {
                                saved= save_to_section_file(dwStartVirt, dwVAddr-dwStartVirt);
                            }
                            if(bOnlyVirtual)
                                debug("v%08lx-%08lx%c %8x\n", dwStartVirt, dwVAddr, saved?'*':' ', dwVAddr-dwStartVirt);
                            else
                                debug("v%08lx-%08lx%c-> p%08lx-%08lx  %8x\n", dwStartVirt, dwVAddr, saved?'*':' ', dwStartPhys, dwPrevPhys+pagesize, dwVAddr-dwStartVirt);
                            bStarted= false;
                        }
                    }
                    if (!bStarted) {
                        bStarted= true;
                        dwStartPhys= dwPhys;
                        dwStartVirt= dwVAddr;
                    }
                    dwPrevPhys= dwPhys;

                }
                dwVAddr+=pagesize;
            }
        }
    }
    if (bStarted) {
        bool saved= false;
        if (!g_savefilename.empty() && is_in_psave_range(dwStartPhys) && is_in_vsave_range(dwStartVirt)) {
            saved= save_to_section_file(dwStartVirt, dwVAddr-dwStartVirt);
        }
        if(bOnlyVirtual)
            debug("v%08lx-%08lx%c %8x\n", dwStartVirt, dwVAddr, saved?'*':' ', dwVAddr-dwStartVirt);
        else
            debug("v%08lx-%08lx%c-> p%08lx-%08lx  %8x\n", dwStartVirt, dwVAddr, saved?'*':' ', dwStartPhys, dwPrevPhys+pagesize, dwVAddr-dwStartVirt);
        bStarted= false;
    }
    return true;
}
bool SummarizeAllSections(bool bOnlyVirtual)
{
    for (DWORD dwSection= 0x02 ; dwSection<0xC4 ; dwSection!=0x7E ? dwSection += 2 : dwSection = 0xC2)
    {
        if (!SummarizeSection(dwSection*0x1000000, bOnlyVirtual))
            return false;
    }
    if (!SummarizePageTable(true, bOnlyVirtual))
        return false;
    return true;
}
DWORD GetProcessSectionSlot(HANDLE hProc)
{
    ProcessInfoMap pmap;
    if (GetProcessInfo(false, pmap))
        if (pmap.find(hProc)!=pmap.end())
            return pmap[hProc].dwMemoryBase;
    return 0xffffffff;
}
void usage()
{
    printf("(C) 2003-2008 Willem jan Hengeveld  itsme@xs4all.nl\n");
    printf("Usage: pmemmap [-v] [-s SECTION | -n NAME | -h HANDLE] [-w file] [-p MIN-MAX]\n");
    printf("    -p specifies the range of phys addrs to save to savefile\n");
    printf("    -a   lists all sections\n");
    printf("    -V MIN-MAX  restricts what virtual addresses of the section are saved.\n");
}
int main( int argc, char *argv[])
{
    DebugStdOut();
    bool bVerbose= false;
    bool bSummarizeAll= false;
    DWORD dwSectionAddr=0xFFFFFFFF;
    char *szProcessName= NULL;
    HANDLE hProcess= INVALID_HANDLE_VALUE;

    std::string vminmaxstring;
    std::string pminmaxstring;

    DebugStdOut();
    for (int i=1 ; i<argc ; i++)
    {
        if (argv[i][0]=='-') switch(argv[i][1])
        {
            case 'v': bVerbose= true; break;
            case 'a': bSummarizeAll= true; break;
            case 's': HANDLEULOPTION(dwSectionAddr, DWORD); break;
            case 'w': HANDLESTROPTION(g_savefilename); break;
            case 'p': HANDLESTROPTION(pminmaxstring); break;
            case 'V': HANDLESTROPTION(vminmaxstring); break;
            case 'h': HANDLEULOPTION(hProcess, HANDLE); break;
            case 'n': HANDLESTROPTION(szProcessName); break;
            default: usage(); 
                     return 1;
        }
        else {
            usage();
            return 1;
        }
    }

    if (pminmaxstring.size()) {
        size_t idx_dash= pminmaxstring.find('-');
        if (idx_dash==pminmaxstring.npos) {
            usage();
            return 1;
        }
        dwPhys_min= strtoul(pminmaxstring.substr(0, idx_dash).c_str(), 0, 0);
        dwPhys_max= strtoul(pminmaxstring.substr(idx_dash+1).c_str(), 0, 0);
    }
    if (vminmaxstring.size()) {
        size_t idx_dash= vminmaxstring.find('-');
        if (idx_dash==vminmaxstring.npos) {
            usage();
            return 1;
        }
        dwVirt_min= strtoul(vminmaxstring.substr(0, idx_dash).c_str(), 0, 0);
        dwVirt_max= strtoul(vminmaxstring.substr(idx_dash+1).c_str(), 0, 0);
    }

    CheckITSDll();

    if (szProcessName)
        hProcess= ITGetProcessHandle(szProcessName);
    if (hProcess!=INVALID_HANDLE_VALUE)
        dwSectionAddr= GetProcessSectionSlot(hProcess);

    if (bSummarizeAll)
        SummarizeAllSections(!bVerbose);
    else if (dwSectionAddr==0xFFFFFFFF)
        SummarizePageTable(bVerbose, false);
    else {
        if (dwVirt_min<0x02000000 && dwVirt_max<0x02000000) {
            dwVirt_min+=dwSectionAddr;
            dwVirt_max+=dwSectionAddr;
        }
        SummarizeSection(dwSectionAddr, !bVerbose);
    }

    if (g_f)
        fclose(g_f);

    StopItsutils();

    return 0;
}


