You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
247 lines
7.8 KiB
247 lines
7.8 KiB
/*
|
|
* Copyright 2002-2019 Intel Corporation.
|
|
*
|
|
* This software is provided to you as Sample Source Code as defined in the accompanying
|
|
* End User License Agreement for the Intel(R) Software Development Products ("Agreement")
|
|
* section 1.L.
|
|
*
|
|
* This software and the related documents are provided as is, with no express or implied
|
|
* warranties, other than those that are expressly stated in the License.
|
|
*/
|
|
|
|
/*
|
|
* This application is a general test of features in the 'pindb' debugger.
|
|
* Since the debugger is not symbolic, the input commands must reference raw
|
|
* addresses in this application not symbol names. Therefore, it would be
|
|
* difficult to keep the addresses in the input commands in sync with
|
|
* addresses in this application. To solve this problem, the application
|
|
* itself can print out the debugger commands. Therefore, to run the test,
|
|
* you run this application twice. The first run generates the debugger
|
|
* command script and the second run executes under the debugger.
|
|
*/
|
|
|
|
#include <iostream>
|
|
#include <fstream>
|
|
#include <string>
|
|
#include <cstring>
|
|
#include "tool_macros.h"
|
|
|
|
#if defined(_MSC_VER)
|
|
typedef unsigned __int64 ADDR;
|
|
#elif defined(__GNUC__)
|
|
#include <stdint.h>
|
|
typedef uint64_t ADDR;
|
|
#endif
|
|
|
|
|
|
static void GenerateBasicScripts(const char *, const char *);
|
|
static void GenerateDetachScripts(const char *, const char *);
|
|
static void GenerateStepCustomBreakScripts(const char *, const char *);
|
|
extern "C" void Breakpoint() ASMNAME("Breakpoint");
|
|
extern "C" void Breakpoint2() ASMNAME("Breakpoint2");
|
|
extern "C" void DoRegMemTest() ASMNAME("DoRegMemTest");
|
|
extern "C" void DoStepCustomBreakTest() ASMNAME("DoStepCustomBreakTest");
|
|
extern "C" long MemTestData[] ASMNAME("MemTestData");
|
|
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
if (argc != 1 && argc != 4)
|
|
{
|
|
std::cerr << "Must specify three arguments or none\n";
|
|
return 1;
|
|
}
|
|
|
|
// When arguments are specified, just generate the
|
|
// debugger scripts.
|
|
//
|
|
if (argc == 4)
|
|
{
|
|
if (std::strcmp(argv[1], "basic") == 0)
|
|
{
|
|
GenerateBasicScripts(argv[2], argv[3]);
|
|
}
|
|
else if (std::strcmp(argv[1], "detach") == 0)
|
|
{
|
|
GenerateDetachScripts(argv[2], argv[3]);
|
|
}
|
|
else if (std::strcmp(argv[1], "step-custom-break") == 0)
|
|
{
|
|
GenerateStepCustomBreakScripts(argv[2], argv[3]);
|
|
}
|
|
else
|
|
{
|
|
std::cerr << "Unknown script name '" << argv[1] << "'\n";
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// When run with no arguments, execute the test code.
|
|
//
|
|
Breakpoint();
|
|
Breakpoint();
|
|
Breakpoint();
|
|
DoRegMemTest();
|
|
DoStepCustomBreakTest();
|
|
std::cout << "Test completed" << std::endl;
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*!
|
|
* Generate the PinDB scripts for the "basic" test.
|
|
*
|
|
* @param[in] inFile Name of the generated PinDB command input file.
|
|
* @param[in] compareFile Name of the generated PinDB expected output comparison file.
|
|
*/
|
|
static void GenerateBasicScripts(const char *inFile, const char *compareFile)
|
|
{
|
|
std::ofstream in(inFile);
|
|
std::ofstream compare(compareFile);
|
|
|
|
ADDR bpAddr1 = reinterpret_cast<ADDR>(&Breakpoint);
|
|
ADDR bpAddr2 = reinterpret_cast<ADDR>(&Breakpoint2);
|
|
ADDR memTestAddr = reinterpret_cast<ADDR>(&DoRegMemTest);
|
|
ADDR memDataAddr = reinterpret_cast<ADDR>(&MemTestData[0]);
|
|
|
|
in << std::hex << std::noshowbase;
|
|
compare << std::hex << std::noshowbase;
|
|
|
|
compare << "Thread .* stopped at\n";
|
|
|
|
// Test breakpoints
|
|
//
|
|
in << "b 0x" << bpAddr1 << "\n";
|
|
in << "b 0x" << bpAddr2 << "\n";
|
|
in << "c\n";
|
|
compare << "Thread .* stopped at 0x" << bpAddr1 << " \\(at breakpoint\\)\n";
|
|
in << "c\n";
|
|
compare << "Thread .* stopped at 0x" << bpAddr2 << " \\(at breakpoint\\)\n";
|
|
in << "c\n";
|
|
compare << "Thread .* stopped at 0x" << bpAddr1 << " \\(at breakpoint\\)\n";
|
|
in << "s\n";
|
|
compare << "Thread .* stopped at 0x" << bpAddr2 << "\n";
|
|
|
|
// Test disassembly
|
|
//
|
|
in << "dis 2 0x" << bpAddr1 << "\n";
|
|
compare << "0x0*" << bpAddr1 << ".*nop\n";
|
|
compare << "0x0*" << bpAddr2 << ".*ret\n";
|
|
|
|
// Test clearing breakpoints. Set up for register & memory tests.
|
|
//
|
|
in << "del 0x" << bpAddr1 << "\n";
|
|
in << "del 0x" << bpAddr2 << "\n";
|
|
in << "b 0x" << memTestAddr << "\n";
|
|
|
|
// Test examine memory.
|
|
//
|
|
in << "x/2w 0x" << memDataAddr << "\n";
|
|
compare << "0x0*" << memDataAddr << " 12345678 deadbeef\n";
|
|
|
|
in << "c\n";
|
|
compare << "Thread .* stopped at 0x" << memTestAddr << " \\(at breakpoint\\)\n";
|
|
in << "s\n";
|
|
in << "s\n";
|
|
#if defined(TARGET_IA32E)
|
|
std::string reg = "rcx";
|
|
#elif defined(TARGET_IA32)
|
|
std::string reg = "ecx";
|
|
#else
|
|
# error "Need TARGET_IA32 or TARGET_IA32E defined"
|
|
#endif
|
|
in << "p $" << reg << "\n";
|
|
compare << "0x0*12345678\n";
|
|
in << "set $" << reg << "=0x123fff\n";
|
|
|
|
in << "s\n";
|
|
|
|
// Examine the modified memory (verifies that we really did change %cx).
|
|
//
|
|
in << "x/2w 0x" << memDataAddr << "\n";
|
|
compare << "0x0*" << memDataAddr << " 00123fff deadbeef\n";
|
|
|
|
// Test that we can modify memory.
|
|
//
|
|
in << "m/1w 0x" << memDataAddr << " 0xccc456\n";
|
|
in << "x/2w 0x" << memDataAddr << "\n";
|
|
compare << "0x0*" << memDataAddr << " 00ccc456 deadbeef\n";
|
|
|
|
// Test that we can send pintool-commands and receive a response.
|
|
//
|
|
in << "monitor stacktrace on\n";
|
|
compare << "Stack tracing enabled.\n";
|
|
in << "monitor stacktrace off\n";
|
|
compare << "Stack tracing disabled.\n";
|
|
|
|
in << "c\n";
|
|
compare << "Program exited with 0\n";
|
|
in << "q\n";
|
|
}
|
|
|
|
|
|
/*!
|
|
* Generate the PinDB scripts for the "detach" test.
|
|
*
|
|
* @param[in] inFile Name of the generated PinDB command input file.
|
|
* @param[in] compareFile Name of the generated PinDB expected output comparison file.
|
|
*/
|
|
static void GenerateDetachScripts(const char *inFile, const char *compareFile)
|
|
{
|
|
std::ofstream in(inFile);
|
|
std::ofstream compare(compareFile);
|
|
|
|
ADDR bpAddr1 = reinterpret_cast<ADDR>(&Breakpoint);
|
|
ADDR bpAddr2 = reinterpret_cast<ADDR>(&Breakpoint2);
|
|
|
|
in << std::hex << std::noshowbase;
|
|
compare << std::hex << std::noshowbase;
|
|
|
|
compare << "Thread .* stopped at\n";
|
|
|
|
// Set some breakpoints. We want to make sure they are not triggered after the detach.
|
|
//
|
|
in << "b 0x" << bpAddr1 << "\n";
|
|
in << "b 0x" << bpAddr2 << "\n";
|
|
|
|
// Do the detach. The application should run to completion.
|
|
//
|
|
in << "detach-and-wait\n";
|
|
compare << "Test completed\n";
|
|
in << "q\n";
|
|
}
|
|
|
|
|
|
/*!
|
|
* Generate the PinDB scripts for the "step-custom-break" test.
|
|
*
|
|
* @param[in] inFile Name of the generated PinDB command input file.
|
|
* @param[in] compareFile Name of the generated PinDB expected output comparison file.
|
|
*/
|
|
static void GenerateStepCustomBreakScripts(const char *inFile, const char *compareFile)
|
|
{
|
|
std::ofstream in(inFile);
|
|
std::ofstream compare(compareFile);
|
|
|
|
ADDR bpAddr = reinterpret_cast<ADDR>(&DoStepCustomBreakTest);
|
|
ADDR watchAddr = reinterpret_cast<ADDR>(&Breakpoint);
|
|
|
|
in << std::hex << std::noshowbase;
|
|
compare << std::hex << std::noshowbase;
|
|
|
|
in << "b 0x" << bpAddr << "\n";
|
|
in << "c\n";
|
|
in << "monitor break if jump to 0x" << watchAddr << "\n";
|
|
in << "s\n"; // step over NOP
|
|
in << "s\n"; // try to step over CALL, but trigger "monitor break"
|
|
in << "s\n"; // step into CALL
|
|
in << "k\n";
|
|
in << "q\n";
|
|
|
|
compare << "Thread .* stopped at .* \\(after step\\)\n"; // step over NOP
|
|
compare << "Thread .* stopped at .* \\(at tool breakpoint\\)\n"; // attempt to step over CALL
|
|
compare << "Triggered breakpoint #1: break if jump to 0x" << watchAddr << "\n";
|
|
compare << "Thread .* stopped at 0x" << watchAddr << " \\(after step\\)\n"; // step into CALL
|
|
}
|