JNI crashing after repeatedly calling a method - java-native-interface

I have some JNI code in a thread that calls from Java to C. The code works but if I put too much pressure on it (execute too many instructions), it will crash:
W/dalvikvm( 1502): JNI local reference table summary (512 entries):
W/dalvikvm( 1502): 512 of Ljava/lang/Class; 164B (1 unique)
W/dalvikvm( 1502): Memory held directly by tracked refs is 164 bytes
E/dalvikvm( 1502): Failed adding to JNI local ref table (has 512 entries)
I/dalvikvm( 1502): "Thread-17" prio=5 tid=10 RUNNABLE
I/dalvikvm( 1502): | group="main" sCount=0 dsCount=0 s=N obj=0x40114910 self=0xd3d40
I/dalvikvm( 1502): | sysTid=1542 nice=0 sched=0/0 cgrp=default handle=821104
I/dalvikvm( 1502): | schedstat=( 359863282 630188006 2660 )
I/dalvikvm( 1502): at dalvik.system.NativeStart.run(Native Method)
I/dalvikvm( 1502):
E/dalvikvm( 1502): VM aborting
I/DEBUG ( 1011): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
I/DEBUG ( 1011): Build fingerprint: 'verizon/voles/sholes/sholes:2.2.2/FRG83G/91102:user/release-keys'
I/DEBUG ( 1011): pid: 1502, tid: 1542 >>> app_process <<<
I/DEBUG ( 1011): signal 11 (SIGSEGV), fault addr deadd00d
I/DEBUG ( 1011): r0 00000026 r1 afd14629 r2 afd14629 r3 00000000
I/DEBUG ( 1011): r4 805a23f4 r5 805a23f4 r6 000d3d40 r7 000d3d90
I/DEBUG ( 1011): r8 00100000 r9 80601f45 10 449f1000 fp 4453ed90
I/DEBUG ( 1011): ip deadd00d sp 44af0dc0 lr afd15673 pc 805420b8 cpsr 20000030
In my call from Java to C, I keep a GlobalReference to the class I want to call and then create a new thread:
JNIEXPORT void JNICALL Java_com_device_client_HostConnection_initialize
(JNIEnv * env, jobject obj, jobject inject)
{
JavaVM *tmpVM;
jint result = env->GetJavaVM(&tmpVM);
if (result < 0) {
LOGE("Error using GetJavaVM\n");
exit(-1);
}
jobject tmpHostObject = env->NewGlobalRef(inject);
if (tmpHostObject == NULL) {
LOGE("ERROR: Run out of memory for weak global ref\n");
exit(-1);
}
vm = tmpVM;
hostObject = tmpHostObject;
pthread_t pth;
pthread_create(&pth, NULL, startServer, NULL);
pthread_join(pth, NULL);
}
Here vm and hostObject are global variables. In my new thread, I call a Java method from the inject object that I passed along and created a GobalRef to:
void *startServer(void* arg)
{
JNIEnv* env = NULL;
jmethodID mid;
jclass hostClass;
vm->AttachCurrentThread(&env, NULL);
while (run) {
/* some code */
/* Calls a new thread */
pthread_t pth;
pthread_create(&pth, NULL, receive, NULL);
/* more code */
}
vm->DetachCurrentThread();
}
void *receive()
{
jmethodID mid;
jclass hostClass;
JNIEnv* env = NULL;
vm->AttachCurrentThread(&env, NULL)
while (1) {
/* receive x, y and action */
hostClass = env->GetObjectClass(hostObject);
mid = env->GetMethodID(hostClass, "executeTouch", "(III)V");
if (mid == 0) {
LOGD("ERROR: GetMethodID\n");
exit(-1);
}
env->CallVoidMethod(hostObject, mid, x * 2, y * 2, action);
}
vm->DetachCurrentThread();
}
Does anyone please know what is going on? I am running out of memory please? Why would that be and how could I please avoid it?
EDIT:
I realized that I didn't need to get the MethodID all the time, I could just store it locally before the while (1). This fixed my problem! Sorry for the issue, thanks.
Thank you very much.

I realized that I didn't need to get the MethodID all the time, I could just store it locally before the while (1). This fixed my problem! Sorry for the issue, thanks.

Related

Kernel Mode Driver BSOD PAGE_FAULT_IN_NONPAGED_AREA using a global UNICODE_STRING in Callback

I get a BSOD issue (PAGE_FAULT_IN_NONPAGED_AREA) it only started happening when I added my UNICODE_STRING
The system crash happens after the UNICODE_STRING is set and working after like 10 minutes or so system crashes out of nowhere. Maybe because I overwrite the UNICODE_STRING many times?
The WinDBG says I need to use a probe() so this error doesn't happen.
do I need to use something like? in the callback before the if statement?
ProbeForRead(ProcessName.Buffer, ProcessName.MaximumLength, sizeof(UCHAR));
Here is my MEMORY.DMP
Microsoft (R) Windows Debugger Version 6.12.0002.633 AMD64
Copyright (c) Microsoft Corporation. All rights reserved.
Loading Dump File [C:\Windows\MEMORY.DMP]
Kernel Summary Dump File: Only kernel address space is available
Symbol search path is: *** Invalid ***
****************************************************************************
* Symbol loading may be unreliable without a symbol search path. *
* Use .symfix to have the debugger choose a symbol path. *
* After setting your symbol path, use .reload to refresh symbol locations. *
****************************************************************************
Executable search path is:
*********************************************************************
* Symbols can not be loaded because symbol path is not initialized. *
* *
* The Symbol Path can be set by: *
* using the _NT_SYMBOL_PATH environment variable. *
* using the -y <symbol_path> argument when starting the debugger. *
* using .sympath and .sympath+ *
*********************************************************************
*** ERROR: Symbol file could not be found. Defaulted to export symbols for ntkrnlmp.exe -
Windows 7 Kernel Version 7601 (Service Pack 1) MP (12 procs) Free x64
Product: WinNt, suite: TerminalServer SingleUserTS
Built by: 7601.24545.amd64fre.win7sp1_ldr_escrow.200102-1707
Machine Name:
Kernel base = 0xfffff800`0340a000 PsLoadedModuleList = 0xfffff800`03643c90
Debug session time: Fri Mar 27 07:18:32.627 2020 (UTC - 4:00)
System Uptime: 0 days 1:14:27.811
*********************************************************************
* Symbols can not be loaded because symbol path is not initialized. *
* *
* The Symbol Path can be set by: *
* using the _NT_SYMBOL_PATH environment variable. *
* using the -y <symbol_path> argument when starting the debugger. *
* using .sympath and .sympath+ *
*********************************************************************
*** ERROR: Symbol file could not be found. Defaulted to export symbols for ntkrnlmp.exe -
Loading Kernel Symbols
...............................................................
................................................................
................................................
Loading User Symbols
PEB is paged out (Peb.Ldr = 00000000`fffdf018). Type ".hh dbgerr001" for details
Loading unloaded module list
...........................
ERROR: FindPlugIns 8007007b
*******************************************************************************
* *
* Bugcheck Analysis *
* *
*******************************************************************************
Use !analyze -v to get detailed debugging information.
BugCheck 50, {fffff8a037f2d000, 0, fffff8000348e46a, 0}
***** Kernel symbols are WRONG. Please fix symbols to do analysis.
Probably caused by : Driver.sys ( Driver!ImageLoadCallback+38 )
Followup: MachineOwner
---------
10: kd> !analyze -v
ERROR: FindPlugIns 8007007b
*******************************************************************************
* *
* Bugcheck Analysis *
* *
*******************************************************************************
PAGE_FAULT_IN_NONPAGED_AREA (50)
Invalid system memory was referenced. This cannot be protected by try-except,
it must be protected by a Probe. Typically the address is just plain bad or it
is pointing at freed memory.
Arguments:
Arg1: fffff8a037f2d000, memory referenced.
Arg2: 0000000000000000, value 0 = read operation, 1 = write operation.
Arg3: fffff8000348e46a, If non-zero, the instruction address which referenced the bad memory
address.
Arg4: 0000000000000000, (reserved)
Debugging Details:
------------------
***** Kernel symbols are WRONG. Please fix symbols to do analysis.
ADDITIONAL_DEBUG_TEXT:
Use '!findthebuild' command to search for the target build information.
If the build information is available, run '!findthebuild -s ; .reload' to set symbol path and load symbols.
MODULE_NAME: Driver
FAULTING_MODULE: fffff8000340a000 nt
DEBUG_FLR_IMAGE_TIMESTAMP: 5e7ddfd8
READ_ADDRESS: unable to get nt!MmSpecialPoolStart
unable to get nt!MmSpecialPoolEnd
unable to get nt!MmPoolCodeStart
unable to get nt!MmPoolCodeEnd
fffff8a037f2d000
FAULTING_IP:
nt!wcsstr+56
fffff800`0348e46a 66418b00 mov ax,word ptr [r8]
MM_INTERNAL_CODE: 0
DEFAULT_BUCKET_ID: VISTA_DRIVER_FAULT
BUGCHECK_STR: 0x50
CURRENT_IRQL: 0
LAST_CONTROL_TRANSFER: from fffff800035779b2 to fffff8000349dea0
STACK_TEXT:
fffff880`0a6abf38 fffff800`035779b2 : 00000000`00000050 fffff8a0`37f2d000 00000000`00000000 fffff880`0a6ac090 : nt!KeBugCheckEx
fffff880`0a6abf40 fffff800`034a9fdc : 00000000`00000000 fffff8a0`37f2d000 fffff880`0a6ac000 fffffa80`232cfe28 : nt!PoCallDriver+0x4f52
fffff880`0a6ac090 fffff800`0348e46a : fffff880`0aeaf498 00000000`00000001 00000000`00001810 00000000`0000003d : nt!longjmp+0x3c7c
fffff880`0a6ac228 fffff880`0aeaf498 : 00000000`00000001 00000000`00001810 00000000`0000003d fffff8a0`0e903c00 : nt!wcsstr+0x56
fffff880`0a6ac230 fffff800`0370f3e4 : 00000000`00000001 fffff800`036250d8 fffff800`036250d8 00000000`00000000 : Driver!ImageLoadCallback+0x38 [c:\users\igor\desktop\driver memory editor\driver\driver.c # 499]
fffff880`0a6ac260 fffff800`03839c92 : fffffa80`232cfdd0 fffffa80`1a26b278 fffffa80`20cc59c0 00000000`00000000 : nt!ObDereferenceSecurityDescriptor+0x204
fffff880`0a6ac2c0 fffff800`036fe317 : fffffa80`20cc5980 fffffa80`1a26b060 fffff880`0a6ac570 fffff880`0a6ac568 : nt!IoCreateController+0x2af2
fffff880`0a6ac410 fffff800`036f5aed : ffff845f`00000018 fffffa80`1a26b060 fffff880`0a6ac570 00000000`00000020 : nt!NtOpenThreadTokenEx+0x14b7
fffff880`0a6ac500 fffff800`034abf53 : 00000000`00002760 fffffa80`1efbfb50 00000000`0021ace8 00000000`00000001 : nt!NtMapViewOfSection+0x2bd
fffff880`0a6ac5d0 00000000`779a9a2a : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : nt!longjmp+0x5bf3
00000000`0021acc8 fffff800`034a0cc0 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : 0x779a9a2a
fffff880`0a6ac820 00000000`00000000 : 00000000`01190b90 fffff880`0a6acd18 fffff900`c085eee0 00000000`0043e0a0 : nt!KiCpuId+0xa10
STACK_COMMAND: kb
FOLLOWUP_IP:
Driver!ImageLoadCallback+38 [c:\users\igor\desktop\driver memory editor\driver\driver.c # 499]
fffff880`0aeaf498 4885c0 test rax,rax
FAULTING_SOURCE_CODE:
495: //DbgPrintEx(0, 0, "Loaded Name: %ls \n", FullImageName->Buffer);
496: //DbgPrintEx(0, 0, "Loaded To Process: %d \n", ProcessId);
497:
498: // Compare our string to input
> 499: if (ProcessName.Length != 0 && wcsstr(FullImageName->Buffer, ProcessName.Buffer)) {
500: // if it matches
501: DbgPrintEx(0, 0, "Loaded Name: %ls \n", FullImageName->Buffer);
502: DbgPrintEx(0, 0, "Loaded To Process: %d \n", ProcessId);
503:
504: GameBaseAddress = ImageInfo->ImageBase;
SYMBOL_STACK_INDEX: 4
SYMBOL_NAME: Driver!ImageLoadCallback+38
FOLLOWUP_NAME: MachineOwner
IMAGE_NAME: Driver.sys
BUCKET_ID: WRONG_SYMBOLS
Followup: MachineOwner
---------
Source code:
// Request to retrieve the process id of game process, from kernel space
#define IO_SET_PROCESS_NAME_REQUEST CTL_CODE(FILE_DEVICE_UNKNOWN, 0x0703 /* Our Custom Code */, METHOD_BUFFERED, FILE_SPECIAL_ACCESS)
ULONG GameProcessId, GameBaseAddress;
UNICODE_STRING ProcessName;
// set a callback for every PE image loaded to user memory
// then find the base address & game.exe process id using the callback
PLOAD_IMAGE_NOTIFY_ROUTINE ImageLoadCallback(PUNICODE_STRING FullImageName,
HANDLE ProcessId, PIMAGE_INFO ImageInfo)
{
//DbgPrintEx(0, 0, "Loaded Name: %ls \n", FullImageName->Buffer);
//DbgPrintEx(0, 0, "Loaded To Process: %d \n", ProcessId);
// Compare our string to input
if (ProcessName.Length != 0 && wcsstr(FullImageName->Buffer, ProcessName.Buffer)) {
// if it matches
DbgPrintEx(0, 0, "Loaded Name: %ls \n", FullImageName->Buffer);
DbgPrintEx(0, 0, "Loaded To Process: %d \n", ProcessId);
GameBaseAddress = ImageInfo->ImageBase;
GameProcessId = ProcessId;
}
}
//Here is my IOCTL Call Handler
// IOCTL Call Handler function
NTSTATUS IoControl(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
NTSTATUS Status;
ULONG BytesIO = 0;
PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);
// Code received from user space
ULONG ControlCode = stack->Parameters.DeviceIoControl.IoControlCode;
if (ControlCode == IO_SET_PROCESS_NAME_REQUEST)
{
ULONG inBufLength = stack->Parameters.DeviceIoControl.InputBufferLength; // Input buffer length
ULONG outBufLength = stack->Parameters.DeviceIoControl.OutputBufferLength; // Output buffer length
if (inBufLength == 0) {
DbgPrint("Invalid Process name size detected\n");
Status = STATUS_INVALID_PARAMETER;
BytesIO = 0;
goto finish;
}
PWSTR processBuffer;
// Allocate the buffer that will contain the string
processBuffer = ExAllocatePoolWithTag(NonPagedPool, stack->Parameters.DeviceIoControl.InputBufferLength+2, '5PWA');
if(processBuffer == NULL){
DbgPrint("Unable to allocate the Process Buffer: not enough memory.\n");
Status = STATUS_INSUFFICIENT_RESOURCES;
BytesIO = 0;
goto finish;
}
// Copy the buffer
RtlCopyBytes((PVOID)processBuffer, Irp->AssociatedIrp.SystemBuffer, stack->Parameters.DeviceIoControl.InputBufferLength);
//RtlMoveMemory((PVOID)processBuffer, Irp->AssociatedIrp.SystemBuffer, stack->Parameters.DeviceIoControl.InputBufferLength);
// Force a \0 at the end of the filename to avoid that malformed strings cause RtlInitUnicodeString to crash the system
((PSHORT)processBuffer)[(stack->Parameters.DeviceIoControl.InputBufferLength+2)/2-1]=0;
// Create the Unicode string
BOOLEAN success = RtlCreateUnicodeString(&ProcessName, processBuffer);
ExFreePool(processBuffer);
if (success) {
DbgPrint("Set New Process to %ws, len=%d\n", ProcessName.Buffer, stack->Parameters.DeviceIoControl.InputBufferLength);
Status = STATUS_SUCCESS;
BytesIO = 0;
} else {
DbgPrint("Failed to allocate Unicode String for Process\n");
Status = STATUS_INSUFFICIENT_RESOURCES;
BytesIO = 0;
}
}
else
{
// if the code is unknown
Status = STATUS_INVALID_PARAMETER;
BytesIO = 0;
}
finish:
// Complete the request
Irp->IoStatus.Status = Status;
Irp->IoStatus.Information = BytesIO;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
}
// Driver Entrypoint
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject,
PUNICODE_STRING pRegistryPath)
{
DbgPrintEx(0, 0, "Driver Loaded\n");
PsSetLoadImageNotifyRoutine(ImageLoadCallback);
RtlInitUnicodeString(&dev, deviceNameBuffer);
RtlInitUnicodeString(&dos, deviceSymLinkBuffer);
IoCreateDevice(pDriverObject, 0, &dev, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &pDeviceObject);
IoCreateSymbolicLink(&dos, &dev);
pDriverObject->MajorFunction[IRP_MJ_CREATE] = CreateCall;
pDriverObject->MajorFunction[IRP_MJ_CLOSE] = CloseCall;
pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = IoControl;
pDriverObject->DriverUnload = UnloadDriver;
pDeviceObject->Flags |= DO_DIRECT_IO;
pDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
return STATUS_SUCCESS;
}
NTSTATUS UnloadDriver(PDRIVER_OBJECT pDriverObject)
{
DbgPrintEx(0, 0, "Unload routine called.\n");
PsRemoveLoadImageNotifyRoutine(ImageLoadCallback);
IoDeleteSymbolicLink(&dos);
IoDeleteDevice(pDriverObject->DeviceObject);
}
NTSTATUS CreateCall(PDEVICE_OBJECT DeviceObject, PIRP irp)
{
irp->IoStatus.Status = STATUS_SUCCESS;
irp->IoStatus.Information = 0;
IoCompleteRequest(irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
NTSTATUS CloseCall(PDEVICE_OBJECT DeviceObject, PIRP irp)
{
irp->IoStatus.Status = STATUS_SUCCESS;
irp->IoStatus.Information = 0;
IoCompleteRequest(irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}

Cannot write to serial

I am using the ESP32 DevKitC-v1 (clone) with FreeRTOS and attempting to write bytes to the serial port.
My code (below) causes the following exception:
Guru Meditation Error: Core 0 panic'ed (LoadProhibited). Exception was unhandled.
Core 0 register dump:
PC : 0x400ea8fe PS : 0x00060730 A0 : 0x800eb825 A1 : 0x3ffdfdf0
A2 : 0x00000001 A3 : 0x00000055 A4 : 0x00000001 A5 : 0x00000000
A6 : 0x00000002 A7 : 0xff000000 A8 : 0x00000000 A9 : 0x60010000
A10 : 0x00000055 A11 : 0x00000001 A12 : 0x3ffdfd54 A13 : 0x3ffd1068
A14 : 0x00000000 A15 : 0x00000000 SAR : 0x00000004 EXCCAUSE: 0x0000001c
EXCVADDR: 0x00000055 LBEG : 0x400014fd LEND : 0x4000150d LCOUNT : 0xffffffff
Backtrace: 0x400ea8fe:0x3ffdfdf0 0x400eb822:0x3ffdfe10 0x400ebf0d:0x3ffdfe50 0x400e1511:0x3ffdfe80
Rebooting...
ets Jun 8 2016 00:22:57
rst:0xc (SW_CPU_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:2
load:0x3fff0018,len:4
load:0x3fff001c,len:6372
load:0x40078000,len:11276
load:0x40080000,len:6084
entry 0x4008032c
I have been able to find limited information regarding FreeRTOS and UART operations, I apologise in advance however if I have missed something obvious. I have been trying to self resolve the issue for about 3 days now.
My code:
#define ECHO_TEST_TXD (GPIO_NUM_17)
#define ECHO_TEST_RXD (GPIO_NUM_16)
#define ECHO_TEST_RTS (UART_PIN_NO_CHANGE)
#define ECHO_TEST_CTS (UART_PIN_NO_CHANGE)
static void prvSerialRelayMQTTCommand()
{
const TickType_t xFiveSeconds = pdMS_TO_TICKS( 5000UL );
/* Configure parameters of an UART driver,
* communication pins and install the driver */
uart_config_t uart_config = {
.baud_rate = 9600,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE
};
uart_param_config(UART_NUM_2, &uart_config);
uart_set_pin(UART_NUM_2, ECHO_TEST_TXD, ECHO_TEST_RXD, ECHO_TEST_RTS, ECHO_TEST_CTS);
uart_driver_install(UART_NUM_2, BUF_SIZE * 2, 0, 0, NULL, 0);
while (1) {
uart_write_bytes(UART_NUM_2, 0b00000000, 1);
vTaskDelay(xFiveSeconds);
uart_write_bytes(UART_NUM_2, 0b00000001, 1);
vTaskDelay(xFiveSeconds);
uart_write_bytes(UART_NUM_2, 0b00000011, 1);
vTaskDelay(xFiveSeconds);
uart_write_bytes(UART_NUM_2, 0b00000111, 1);
vTaskDelay(xFiveSeconds);
uart_write_bytes(UART_NUM_2, 0b00001111, 1);
vTaskDelay(xFiveSeconds);
}
}
Invalid pointer arguments
The second argument to uart_write_bytes() should be a const char * (see reference). You are passing it an invalid pointer.
Change
uart_write_bytes(UART_NUM_2, 0b00000000, 1);
to
char c = '\0';
uart_write_bytes(UART_NUM_2, &c, 1);
and similarly for the other calls.
However, this isn't necessarily your only problem.
Stack size for FreeRTOS task
A LoadProhibited error occurs when the ESP32 attempts to read or write an invalid memory address. The relevant address is stored in the EXCVADDR register - which in this case we can see is 0x00000055. This means that your calls to uart_write_bytes() (even though invalid) are not the cause of the reset - because you did not pass the address 0x00000055 in any of the calls.
I suspect your problem is that you are not allocating a large enough stack for your FreeRTOS task. If you create a task with a stack size of configMINIMAL_STACK_SIZE, for example, that might not be enough for using the UART. A stack overflow would also result in a LoadProhibited error.
The stack size is the third parameter passed to xTaskCreate(). Try verifying that it is at least 1024, and increase as needed.

C++ Stack Using Linked List Double Delete Issue

I have been looking around quite a bit and I haven't been able to find a solution. For my data structures course, I was asked to create a stack using a linked list. For the most part it works well, my professor even gave me a 24/25 on the assignment, but it has been bothering me that it crashes still. I suspect the issue lies within the copy constructor or the pop operation. Here is the header file:
/*******************************************************************************
*** DESCRIPTION : This file implements a stack ADT using a linked list. ***
*** Besides the standard constructor, copy, and destructor ***
*** functions, the available functions include: ***
*** * push - pushes data onto the stack ***
*** * pop - pops data from the stack ***
*** * peek - view the top element on the stack ***
*** * view - output every element on the stack ***
*******************************************************************************/
#ifndef _KIELASJC2_H
#define _KIELASJC2_H
// User specified element type
typedef char ElementType;
class StackType{
// Exportable definitions
public:
// Constructor
StackType();
// Copy constructor
StackType( StackType& copyStack );
// Destructor
~StackType();
// Push data onto the stack
void push( const ElementType pushElem );
// Pop data from the stack
void pop( ElementType& popElem );
// Peek the top element on the stack without changing the stack
void peek( ElementType& peekElem );
// Look at every element in the stack without changing the stack
void view();
private:
// Non-exportable definitions
struct NodeType;
typedef NodeType* PointerType;
struct NodeType{
ElementType element;
PointerType next;
};
PointerType theTop;
bool isEmpty( PointerType tempNode );
bool isFull( PointerType tempNode );
};
#endif
And here is the implementation file:
/*******************************************************************************
*** DESCRIPTION : This file implements a stack ADT using a linked list. ***
*** Besides the standard constructor, copy, and destructor ***
*** functions, the available functions include: ***
*** * push - pushes data onto the stack ***
*** * pop - pops data from the stack ***
*** * peek - view the top element on the stack ***
*** * view - output every element on the stack ***
*** It also includes two private functions: ***
*** * isEmpty - checks to see if the stack is empty ***
*** * isFull - checks to make sure temp wasn't NULL ***
*******************************************************************************/
#include <iostream> // For using cout
#include <iomanip> // For manipulating output
#include "kielasjc2.h" // Header to this implementation file
// Debug
#define DEBUG 0
// Namespace
using namespace std;
/*******************************************************************************
*** FUNCTION Constructor ***
********************************************************************************
*** DESCRIPTION : Initializes the class by setting theTop and tempNode to ***
*** NULL. ***
*** INPUT ARGS : NONE ***
*** OUTPUT ARGS : NONE ***
*** IN/OUT ARGS : NONE ***
*** RETURN : NONE ***
*******************************************************************************/
StackType::StackType() {
// Initialize both top and temp to NULL
theTop = NULL;
}
/*******************************************************************************
*** FUNCTION Copy Constructor ***
********************************************************************************
*** DESCRIPTION : Creates a copy of the stack linked list by popping all ***
*** elements in the first stack into a temporary stack. All ***
*** elements from the temporary stack are then pushed back ***
*** into the copied stack and original stack. ***
*** INPUT ARGS : NONE ***
*** OUTPUT ARGS : StackType& copyStack - copy of the original stack ***
*** IN/OUT ARGS : NONE ***
*** RETURN : NONE ***
*******************************************************************************/
StackType::StackType( StackType& copyStack ) {
// Point the top to NULL
theTop = NULL;
// Create a temporary stack
StackType tempStack;
// Create a temporary element
ElementType tempElem;
// Create a temporary pointer to the top
//PointerType tempNode = theTop;
// Create a temporary pointer to the the top of the copy stack
//PointerType tempTempNode = tempStack.theTop;
//PointerType copyTempNode = copyStack.theTop;
// Loop through the entire stack and pop each element into the temp stack
while ( !copyStack.isEmpty( copyStack.theTop ) ) {
// Pop the current stack
copyStack.pop( tempElem );
// Push the popped element into the temp stack
tempStack.push( tempElem );
}
// Refill the current and copy stacks with the temp stack
while (!tempStack.isEmpty( tempStack.theTop )){
// Pop the temp stack
tempStack.pop( tempElem );
// Push the popped element onto the current newly copied stack
push( tempElem );
// Push the same popped element back onto the copy stack
copyStack.push( tempElem );
}
}
/*******************************************************************************
*** FUNCTION Destructor ***
********************************************************************************
*** DESCRIPTION : Destroys the current stack by popping every element. ***
*** INPUT ARGS : NONE ***
*** OUTPUT ARGS : NONE ***
*** IN/OUT ARGS : NONE ***
*** RETURN : NONE ***
*******************************************************************************/
StackType::~StackType() {
// Create a temporary element just so we can call pop
ElementType tempElem;
#if DEBUG
cout << "[+] DEBUG: FUNCTION - Destructor" << endl;
cout << "[+] theTop: " << theTop << endl;
#endif
// While the stack is not empty, pop
while (!isEmpty( theTop )) {
// Pop the top node
pop( tempElem );
}
}
/*******************************************************************************
*** FUNCTION push ***
********************************************************************************
*** DESCRIPTION : Pushes the input element onto the current stack. ***
*** INPUT ARGS : const ElementType pushElem - element to be pushed onto ***
*** the current stack. ***
*** OUTPUT ARGS : NONE ***
*** IN/OUT ARGS : NONE ***
*** RETURN : NONE ***
*******************************************************************************/
void StackType::push( const ElementType pushElem ) {
// Create a pointer to a new node
PointerType tempNode = new (nothrow) NodeType;
// Verify that the node isn't full
if (isFull( tempNode )) {
// Tell the user if new memory couldn't be allocated
cout << "[!] ERROR: (push) New dynamic node could not be created.";
cout << endl;
return;
}
#if DEBUG
ElementType tempElem;
cout << "[+] DEBUG: FUNCTION - push" << endl;
peek( tempElem );
cout << "[+] top before the push: " << tempElem << endl;
cout << "[+] Top ptr before: " << theTop << endl;
#endif
// Set the temporary node element to the element being pushed
tempNode->element = pushElem;
// Set the next pointer to the top
tempNode->next = theTop;
// If these two lines were flipped, the code works, but it creates a memory
// leak, so that doesnt work either
theTop = tempNode;
tempNode = NULL;
#if DEBUG
peek( tempElem );
cout << "[+] Top ptr after: " << theTop << endl;
cout << "[+] top after the push: " << tempElem << endl;
#endif
}
/*******************************************************************************
*** FUNCTION pop ***
********************************************************************************
*** DESCRIPTION : Pops the top element off of the current stack. ***
*** INPUT ARGS : NONE ***
*** OUTPUT ARGS : ElementType& popElem - Stores the element that was ***
*** popped from the stack.
*** IN/OUT ARGS : NONE ***
*** RETURN : NONE ***
*******************************************************************************/
void StackType::pop( ElementType& popElem ) {
// Create a temporary pointer
PointerType tempNode = theTop;
// Point temp to the same node the top is pointing to
//tempNode = theTop;
// Make sure the stack isn't empty
if (isEmpty( tempNode )) {
// Tell the user if the stack is empty
cout << "[!] ERROR: (pop) No node available to pop, stack is empty.";
cout << endl;
return;
}
#if DEBUG
cout << "[+] DEBUG: FUNCTION - pop" << endl;
cout << "[+] Top ptr before: " << theTop << endl;
#endif
// Point the top to the next node
theTop = theTop->next;
// Derefrence the next node of the current node being popped
tempNode->next = NULL;
// Pop the element into popElem
popElem = tempNode->element;
// Delete the node
delete tempNode;
// Point temp back to NULL
tempNode = NULL;
#if DEBUG
cout << "[+] Top ptr after: " << theTop << endl;
cout << "[+] Element being popped: " << popElem << endl;
#endif
}
/*******************************************************************************
*** FUNCTION peek ***
********************************************************************************
*** DESCRIPTION : Looks at the top element of the current stack by popping ***
*** it. The element is then pushed back onto the top of the ***
*** current stack. ***
*** INPUT ARGS : NONE ***
*** OUTPUT ARGS : ElementType& peekElem - stores the element being peeked. ***
*** IN/OUT ARGS : NONE ***
*** RETURN : NONE ***
*******************************************************************************/
void StackType::peek( ElementType& peekElem ) {
// Create a temporary pointer
//PointerType tempNode;
// Point temp to the top
//tempNode = theTop;
// Make sure the stack isn't empty
if (isEmpty( theTop )) {
// Tell the user if the stack is empty
cout << "[!] ERROR: (peek) Stack is empty, no element to peek at.";
cout << endl;
// Return a null value if the stack is empty
peekElem = '\0';
return;
}
// Pop the top element into peekElem
pop( peekElem );
// Push the popped element back onto the top of the stack
push( peekElem );
#if DEBUG
cout << "[+] DEBUG: FUNCTION - peek" << endl;
cout << "[+] Peeked value: " << peekElem << endl;
#endif
}
/*******************************************************************************
*** FUNCTION view ***
********************************************************************************
*** DESCRIPTION : Shows the user every element on the current stack by ***
*** popping every element and pushing them into a temporary ***
*** stack. Once the user has seen the contents of the stack, ***
*** the elements on the temporary stack are popped and ***
*** pushed back onto the current stack. ***
*** INPUT ARGS : NONE ***
*** OUTPUT ARGS : NONE ***
*** IN/OUT ARGS : NONE ***
*** RETURN : NONE ***
*******************************************************************************/
void StackType::view() {
// Create a temporary stack
StackType tempStack;
// Create a temporary element
ElementType tempElem;
// Point a temporary node to the top
//PointerType tempNode = theTop;
// Point a temporary node to the top of the copy stack
//PointerType copyTempNode;
// View output for the user
cout << "The Top -> ";
// Loop through the entire stack and pop each element into the temp stack
while (!isEmpty( theTop )) {
// Pop the current stack
pop( tempElem );
// Push the popped element into the temp stack
tempStack.push( tempElem );
// Output the elements as the stack is popped
cout << tempElem << " -> ";
}
cout << "The Bottom" << endl;
// Refill the current stack with the temp stack
while (!tempStack.isEmpty( tempStack.theTop )){
// Pop the temp stack
tempStack.pop( tempElem );
// Push the popped element onto the current stack
push( tempElem );
}
}
/*******************************************************************************
*** FUNCTION isEmpty ***
********************************************************************************
*** DESCRIPTION : Checks to see whether or not the stack is empty. ***
*** INPUT ARGS : NONE ***
*** OUTPUT ARGS : NONE ***
*** IN/OUT ARGS : NONE ***
*** RETURN : bool true/false - true if the stack is empty, false ***
*** if the stack is not empty. ***
*******************************************************************************/
bool StackType::isEmpty( PointerType tempNode ) {
// If the top isn't pointing to NULL, our stack isn't empty yet
if (tempNode != NULL) {
return false;
} else {
return true;
}
}
/*******************************************************************************
*** FUNCTION isFull ***
********************************************************************************
*** DESCRIPTION : Checks to see if the current stack is full after ***
*** attempting to allocate new memory for the next node. ***
*** This will only provide a relevent value if it is used ***
*** immediately after trying to allocate memory for a new ***
*** node being pointed to by the tempNode. ***
*** INPUT ARGS : NONE ***
*** OUTPUT ARGS : NONE ***
*** IN/OUT ARGS : NONE ***
*** RETURN : bool true/false - true if the tempNode is NULL, false ***
*** if a pointer value was assigned to tempNode. ***
*******************************************************************************/
bool StackType::isFull( PointerType tempNode ) {
// If temp isn't NULL, we have successfully allocated memory.
// This function should only be used immediately after allocating new
// memory to the tempNode.
if (tempNode != NULL) {
return false;
} else {
return true;
}
}
This is my test code:
#include <iostream>
#include "kielasjc2.h"
using namespace std;
int main(int argc, char* argv[]) {
StackType stack;
StackType stack2;
stack.push('a');
stack2 = stack;
cout << "Stack: ";
stack.view();
cout << endl;
cout << "Stack2: ";
stack2.view();
cout << endl;
}
Finally, this is the output (including the error) I receive:
Stack: The Top -> a -> The Bottom
Stack2: The Top -> a -> The Bottom
*** glibc detected *** ./a.out: double free or corruption (fasttop): 0x0000000001d78010 ***
======= Backtrace: =========
/lib64/libc.so.6(+0x75f3e)[0x7f9b25fb0f3e]
/lib64/libc.so.6(+0x78d8d)[0x7f9b25fb3d8d]
./a.out[0x400c67]
./a.out[0x400b35]
./a.out[0x400f50]
/lib64/libc.so.6(__libc_start_main+0xfd)[0x7f9b25f59d1d]
./a.out[0x400919]
======= Memory map: ========
00400000-00402000 r-xp 00000000 00:15 9699818 /users/csc300/kielasjc/CSC300/A2_Stack_ADT/a.out
00601000-00602000 rw-p 00001000 00:15 9699818 /users/csc300/kielasjc/CSC300/A2_Stack_ADT/a.out
01d78000-01d99000 rw-p 00000000 00:00 0 [heap]
7f9b20000000-7f9b20021000 rw-p 00000000 00:00 0
7f9b20021000-7f9b24000000 ---p 00000000 00:00 0
7f9b25f3b000-7f9b260c5000 r-xp 00000000 fd:00 917513 /lib64/libc-2.12.so
7f9b260c5000-7f9b262c5000 ---p 0018a000 fd:00 917513 /lib64/libc-2.12.so
7f9b262c5000-7f9b262c9000 r--p 0018a000 fd:00 917513 /lib64/libc-2.12.so
7f9b262c9000-7f9b262cb000 rw-p 0018e000 fd:00 917513 /lib64/libc-2.12.so
7f9b262cb000-7f9b262cf000 rw-p 00000000 00:00 0
7f9b262cf000-7f9b262e5000 r-xp 00000000 fd:00 917506 /lib64/libgcc_s-4.4.7-20120601.so.1
7f9b262e5000-7f9b264e4000 ---p 00016000 fd:00 917506 /lib64/libgcc_s-4.4.7-20120601.so.1
7f9b264e4000-7f9b264e5000 rw-p 00015000 fd:00 917506 /lib64/libgcc_s-4.4.7-20120601.so.1
7f9b264e5000-7f9b26568000 r-xp 00000000 fd:00 917544 /lib64/libm-2.12.so
7f9b26568000-7f9b26767000 ---p 00083000 fd:00 917544 /lib64/libm-2.12.so
7f9b26767000-7f9b26768000 r--p 00082000 fd:00 917544 /lib64/libm-2.12.so
7f9b26768000-7f9b26769000 rw-p 00083000 fd:00 917544 /lib64/libm-2.12.so
7f9b26769000-7f9b26851000 r-xp 00000000 fd:00 1049574 /usr/lib64/libstdc++.so.6.0.13
7f9b26851000-7f9b26a51000 ---p 000e8000 fd:00 1049574 /usr/lib64/libstdc++.so.6.0.13
7f9b26a51000-7f9b26a58000 r--p 000e8000 fd:00 1049574 /usr/lib64/libstdc++.so.6.0.13
7f9b26a58000-7f9b26a5a000 rw-p 000ef000 fd:00 1049574 /usr/lib64/libstdc++.so.6.0.13
7f9b26a5a000-7f9b26a6f000 rw-p 00000000 00:00 0
7f9b26a6f000-7f9b26a8f000 r-xp 00000000 fd:00 917528 /lib64/ld-2.12.so
7f9b26c7d000-7f9b26c82000 rw-p 00000000 00:00 0
7f9b26c8b000-7f9b26c8e000 rw-p 00000000 00:00 0
7f9b26c8e000-7f9b26c8f000 r--p 0001f000 fd:00 917528 /lib64/ld-2.12.so
7f9b26c8f000-7f9b26c90000 rw-p 00020000 fd:00 917528 /lib64/ld-2.12.so
7f9b26c90000-7f9b26c91000 rw-p 00000000 00:00 0
7ffe362e8000-7ffe362fd000 rw-p 00000000 00:00 0 [stack]
7ffe36359000-7ffe3635a000 r-xp 00000000 00:00 0 [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
Aborted
stack2 = stack; doesn't call your copy constructor. It calls a compiler-generated copy-assignment operator, which simply does stack2.theTop = stack.theTop. Whereupon you end up with two objects thinking they both own the same set of nodes.
See also: https://en.wikipedia.org/wiki/Rule_of_three_(C%2B%2B_programming)

BeagleBone Black interrupts through kernel driver

I'm trying to work with interruptions but I get the following error, due to ioread32.
As I have seen in the chapter "25.3.3 Interrupt Features" of "AM335x SitaraTM Processors - Technical Reference Manual"
In order to generate an interrupt request to a host processor upon a defined event (level or logic transition) occurring on a GPIO pin, the GPIO configuration registers have to be programmed as follows:
• Interrupts for the GPIO channel must be enabled in the GPIO_IRQSTATUS_SET_0 and/or GPIO_IRQSTATUS_SET_1 registers.
• The expected event(s) on input GPIO to trigger the interrupt request has to be selected in the GPIO_LEVELDETECT0, GPIO_LEVELDETECT1, GPIO_RISINGDETECT, and GPIO_FALLINGDETECT registers.
[ 1737.604270] Loading hello_interrupts module...
[ 1737.604426] HI: Initialized GPIO #36 to IRQ #164
[ 1737.604478] Unhandled fault: external abort on non-linefetch (0x1028) at 0xfa1ac02c
[ 1737.612611] Internal error: : 1028 [#1] SMP THUMB2
[ 1737.617696] Modules linked in: hello_interrupts(O+) g_multi libcomposite omap_rng mt7601Usta(O) [last unloaded: hello_interrupts]
[ 1737.630128] CPU: 0 Tainted: G O (3.8.13-bone67 #1)
[ 1737.636513] PC is at hello_interrupts_start+0x8b/0x123 [hello_interrupts]
[ 1737.643717] LR is at _raw_read_unlock+0x7/0x8
[ 1737.648340] pc : [<bf8f508c>] lr : [<c04cfaf7>] psr: 80000033
[ 1737.648340] sp : df3fde60 ip : 00000034 fp : c006a001
[ 1737.660481] r10: 00000001 r9 : de594200 r8 : bf8f5001
[ 1737.666011] r7 : 00000000 r6 : bf8f30b8 r5 : 00000000 r4 : fa1ac000
[ 1737.672920] r3 : 48000000 r2 : 00000000 r1 : 481adfff r0 : fa1ac000
[ 1737.679839] Flags: Nzcv IRQs on FIQs on Mode SVC_32 ISA Thumb Segment user
[ 1737.687569] Control: 50c5387d Table: 9f740019 DAC: 00000015
[ 1737.693655] Process insmod (pid: 3040, stack limit = 0xdf3fc240)
[ 1737.700025] Stack: (0xdf3fde60 to 0xdf3fe000)
[ 1737.704659] de60: bf8f30b8 00000000 00400100 df3fc000 c08b5740 c000867f 00000000 de5c3640
[ 1737.713323] de80: 00000000 00000000 00400100 bf8f326c bf8f3260 00000001 bf8f32a8 00000001
[ 1737.721988] dea0: c006a001 c006bd31 bf8f326c 00007fff c0069101 e0dd7000 e0dd6fff bf8f3260
[ 1737.730655] dec0: 00000000 b6f7dd50 df3fc000 bf8f33b4 e0dd6691 c02520d0 6e72656b 00006c65
[ 1737.739320] dee0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[ 1737.747993] df00: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[ 1737.756662] df20: 00000000 00000000 00000000 c0790a68 20000033 000016a8 b6fa2000 b6f7dd50
[ 1737.765331] df40: 00000080 c000c9e4 df3fc000 00000000 00000000 c006c26f e0dd5000 000016a8
[ 1737.774000] df60: e0dd5ae0 e0dd599f e0dd64c8 000003c8 000004c8 00000000 00000000 00000000
[ 1737.782670] df80: 0000001c 0000001d 00000014 00000012 00000010 00000000 00000000 b6fc0088
[ 1737.791339] dfa0: b6fc0d00 c000c841 00000000 b6fc0088 b6fa2000 000016a8 b6f7dd50 00000002
[ 1737.800008] dfc0: 00000000 b6fc0088 b6fc0d00 00000080 00000000 b6f7dd50 000016a8 00000000
[ 1737.808671] dfe0: 00000000 beb7969c b6f77b07 b6f01fd4 80000010 b6fa2000 c0c92420 c0c92440
[ 1737.817378] [<bf8f508c>] (hello_interrupts_start+0x8b/0x123 [hello_interrupts]) from [<c000867f>] (do_one_initcall+0x1f/0xf4)
[ 1737.829367] [<c000867f>] (do_one_initcall+0x1f/0xf4) from [<c006bd31>] (load_module+0x10d5/0x15b0)
[ 1737.838872] [<c006bd31>] (load_module+0x10d5/0x15b0) from [<c006c26f>] (sys_init_module+0x63/0x88)
[ 1737.848379] [<c006c26f>] (sys_init_module+0x63/0x88) from [<c000c841>] (ret_fast_syscall+0x1/0x46)
[ 1737.857867] Code: 4825 f3d4 debb e036 (6ac5) f3bf
[ 1737.884765] ---[ end trace cbd53ac03b070f86 ]---
This is my code:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/irq.h>
MODULE_AUTHOR("MGE");
MODULE_DESCRIPTION("A sample driver using interrupts");
MODULE_LICENSE("GPL");
// GPIO Bank 2
#define GPIO2_START_ADDR 0x481AC000
#define GPIO2_SIZE (0x481ADFFF - GPIO2_START_ADDR)
// GPIO memory-mapped register addresses.
#define GPIO_IRQSTATUS_0 0x2C
#define GPIO_IRQSTATUS_1 0x30
#define GPIO_RISINGDETECT 0x148
#define GPIO_FALLINGDETECT 0x14C
#define PIN_A_GPIO 36
#define PIN_A_FLAGS GPIOF_IN
#define PIN_A_LABEL "HI_PIN_A"
static irqreturn_t irq_handler_pin_a (int irq, void *dev_id) {
printk (KERN_INFO "Hello from irq_handler_pin_a...\n");
return IRQ_HANDLED;
}
static int __init hello_interrupts_start (void) {
int retval, irq, regval;
void __iomem *mem;
printk (KERN_INFO "Loading hello_interrupts module...\n");
/**
* Request the GPIO lines for the IRQ channels.
*/
retval = gpio_request_one(PIN_A_GPIO, PIN_A_FLAGS, PIN_A_LABEL);
if (retval) {
printk (KERN_ERR "HI: Error: Failed to request GPIO pin#%i for IRQ (error %i)\n", PIN_A_GPIO, retval);
// return -retval;
}
irq = gpio_to_irq (PIN_A_GPIO);
if (irq < 0) {
printk (KERN_ERR "HI: ERROR: Failed to obtain IRQ number for GPIO #%i (error %i)\n", PIN_A_GPIO, irq);
// return -irq;
}
retval = request_irq (irq, irq_handler_pin_a, 0 /*IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING*/, PIN_A_LABEL, NULL);
irq_set_irq_type (irq, IRQ_TYPE_EDGE_BOTH);
if (retval) {
printk (KERN_ERR "HI: ERROR: The requested IRQ line#%i from GPIO#%i (error %i)\n", irq, PIN_A_GPIO, retval);
// return -retval;
}
else {
printk (KERN_INFO "HI: Initialized GPIO #%i to IRQ #%i\n", PIN_A_GPIO, irq);
}
/**
* Setup the IRQ registers with the appropriate values.
*/
mem = ioremap(GPIO2_START_ADDR, GPIO2_SIZE);
if(!mem) {
printk (KERN_ERR "HI: ERROR: Failed to remap memory for GPIO Bank 2 IRQ pin configuration.\n");
return 0;
}
// Enable the IRQ ability for GPIO_66.
regval = ioread32 (mem + GPIO_IRQSTATUS_0);
regval |= (1 << 2);
iowrite32 (regval, mem + GPIO_IRQSTATUS_0);
regval = ioread32 (mem + GPIO_IRQSTATUS_1);
regval |= (1 << 2);
iowrite32 (regval, mem + GPIO_IRQSTATUS_1);
// Set GPIO_66 for rising and falling edge detection.
regval = ioread32 (mem + GPIO_RISINGDETECT);
regval |= (1 << 2);
iowrite32(regval, mem + GPIO_RISINGDETECT);
regval = ioread32 (mem + GPIO_FALLINGDETECT);
regval |= (1 << 2);
iowrite32 (regval, mem + GPIO_FALLINGDETECT);
// Release the mapped memory.
iounmap (mem);
return 0;
}
static void __exit hello_interrupts_end(void) {
printk ("HI: Releasing IRQ resources...\n");
free_irq (gpio_to_irq (PIN_A_GPIO), NULL);
gpio_free (PIN_A_GPIO);
printk (KERN_INFO "Goodbye hello_interrupts!\n");
}
module_init (hello_interrupts_start);
module_exit (hello_interrupts_end);
Any idea?
Thanks
The problem was that the GPIO2 module clocks was disabled.
"8.1.12.1.30 CM_PER_GPIO2_CLKCTRL Register (offset = B0h) [reset = 30000h]" of "AM335x SitaraTM Processors - Technical Reference Manual"
Bits 1-0:
Control the way mandatory clocks are managed.
0x0 = DISABLED : Module is disable by SW. Any OCP access to module results in an error, except if resulting from a module wakeup (asynchronous wakeup).
0x1 = RESERVED_1 : Reserved
0x2 = ENABLE : Module is explicitly enabled. Interface clock (if not used for functions) may be gated according to the clock domain state. Functional clocks are guarantied to stay present. As long as in this configuration, power domain sleep transition cannot happen.
0x3 = RESERVED : Reserved
For the above code to work, the GPIO2 clock has to be enabled using the CM_PER_GPIO2_CLKCTRL register and a GPIO pin from GPIO2 has to be choosen. In the code above, GPIO 36 was used, which is on GPIO1 (and anyway used by the internal flash). The following code enables the GPIO2 clock and uses GPIO 68 (which is on header P9 pin 10 btw):
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/irq.h>
MODULE_AUTHOR("MGE");
MODULE_DESCRIPTION("A sample driver using interrupts");
MODULE_LICENSE("GPL");
// GPIO Bank 2
#define GPIO2_START_ADDR 0x481AC000
#define GPIO2_SIZE (0x481ADFFF - GPIO2_START_ADDR)
// CM_PER (Clock Module Peripheral Registers
#define CM_PER_START_ADDR 0x44e00000
#define CM_PER_SIZE 0x400
#define CM_PER_GPIO2_CLKCTRL 0xb0
// GPIO memory-mapped register addresses.
#define GPIO_IRQSTATUS_0 0x2C
#define GPIO_IRQSTATUS_1 0x30
#define GPIO_RISINGDETECT 0x148
#define GPIO_FALLINGDETECT 0x14C
#define PIN_A_GPIO 68 // is on P9 pin 10
#define PIN_A_FLAGS GPIOF_IN
#define PIN_A_LABEL "HI_PIN_A"
static irqreturn_t irq_handler_pin_a (int irq, void *dev_id) {
printk (KERN_INFO "Hello from irq_handler_pin_a...\n");
return IRQ_HANDLED;
}
static int __init hello_interrupts_start (void) {
int retval, irq, regval;
void __iomem *mem;
void __iomem *cm_per;
printk (KERN_INFO "Loading hello_interrupts module...\n");
/**
* Request the GPIO lines for the IRQ channels.
*/
retval = gpio_request_one(PIN_A_GPIO, PIN_A_FLAGS, PIN_A_LABEL);
if (retval) {
printk (KERN_ERR "HI: Error: Failed to request GPIO pin#%i for IRQ (error %i)\n", PIN_A_GPIO, retval);
// return -retval;
}
irq = gpio_to_irq (PIN_A_GPIO);
if (irq < 0) {
printk (KERN_ERR "HI: ERROR: Failed to obtain IRQ number for GPIO #%i (error %i)\n", PIN_A_GPIO, irq);
// return -irq;
}
retval = request_irq (irq, irq_handler_pin_a, 0 /*IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING*/, PIN_A_LABEL, NULL);
irq_set_irq_type (irq, IRQ_TYPE_EDGE_BOTH);
if (retval) {
printk (KERN_ERR "HI: ERROR: The requested IRQ line#%i from GPIO#%i (error %i)\n", irq, PIN_A_GPIO, retval);
// return -retval;
}
else {
printk (KERN_INFO "HI: Initialized GPIO #%i to IRQ #%i\n", PIN_A_GPIO, irq);
}
/*
Enable GPIO2 clock
*/
cm_per = ioremap(CM_PER_START_ADDR, CM_PER_SIZE);
if(!cm_per) {
printk (KERN_ERR "HI: ERROR: Failed to remap memory for CM_PER.\n");
return 0;
}
iowrite32(0x02, cm_per + CM_PER_GPIO2_CLKCTRL);
iounmap(cm_per);
/**
* Setup the IRQ registers with the appropriate values.
*/
mem = ioremap(GPIO2_START_ADDR, GPIO2_SIZE);
if(!mem) {
printk (KERN_ERR "HI: ERROR: Failed to remap memory for GPIO Bank 2 IRQ pin configuration.\n");
return 0;
}
// Enable the IRQ ability for GPIO_66.
regval = ioread32 (mem + GPIO_IRQSTATUS_0);
regval |= (1 << 2);
iowrite32 (regval, mem + GPIO_IRQSTATUS_0);
regval = ioread32 (mem + GPIO_IRQSTATUS_1);
regval |= (1 << 2);
iowrite32 (regval, mem + GPIO_IRQSTATUS_1);
// Set GPIO_66 for rising and falling edge detection.
regval = ioread32 (mem + GPIO_RISINGDETECT);
regval |= (1 << 2);
iowrite32(regval, mem + GPIO_RISINGDETECT);
regval = ioread32 (mem + GPIO_FALLINGDETECT);
regval |= (1 << 2);
iowrite32 (regval, mem + GPIO_FALLINGDETECT);
// Release the mapped memory.
iounmap (mem);
return 0;
}
static void __exit hello_interrupts_end(void) {
printk ("HI: Releasing IRQ resources...\n");
free_irq (gpio_to_irq (PIN_A_GPIO), NULL);
gpio_free (PIN_A_GPIO);
printk (KERN_INFO "Goodbye hello_interrupts!\n");
}
module_init (hello_interrupts_start);
module_exit (hello_interrupts_end);

Creating dump file at the moment of access violation

I would like to create process dump file at the moment when access violation that will not be handled occurred.
Currently, I have registered mine, unhandled exception callback with:
SetUnhandledExceptionFilter(CustomUnhandledExceptionFilter);
CustomUnhandledExceptionFilter creates dump file and prints call stack.
But this approach has one flaw - it is done when AV has already happened, AV exception is thrown and has not been handled by thread it happened in. Unhandled exception callback is called when exception is about to leave thread scope and dump created at this point has no local variables of function that exception occurred since stack pointer is lost.
Is there an way to over come this? I would like to take a look at stack of thread that got AV at the moment AV happened.
VS
#include "stdafx.h"
#include <windows.h>
#include <dbghelp.h>
LONG WINAPI MyUnhandledExceptionFilter(EXCEPTION_POINTERS *ExceptionInfo)
{
HANDLE hFile = CreateFile(
L"proc.dmp",
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL
);
MINIDUMP_EXCEPTION_INFORMATION mei;
mei.ThreadId = GetCurrentThreadId();
mei.ClientPointers = TRUE;
mei.ExceptionPointers = ExceptionInfo;
MiniDumpWriteDump(
GetCurrentProcess(),
GetCurrentProcessId(),
hFile,
MiniDumpNormal,
&mei,
NULL,
NULL);
return EXCEPTION_EXECUTE_HANDLER;
}
int _tmain(int argc, _TCHAR* argv[])
{
SetUnhandledExceptionFilter(MyUnhandledExceptionFilter);
int* p = NULL;
*p = 1;
return 0;
}
WinDbg
Microsoft (R) Windows Debugger Version 6.12.0002.633 X86
Copyright (c) Microsoft Corporation. All rights reserved.
Loading Dump File [D:\Documents\Visual Studio 2012\Projects\Test\Debug\proc.dmp]
User Mini Dump File: Only registers, stack and portions of memory are available
Symbol search path is: SRV*C:\Symbols*http://msdl.microsoft.com/download/symbols
Executable search path is:
Windows 7 Version 7600 UP Free x86 compatible
Product: WinNt, suite: SingleUserTS
Machine Name:
Debug session time: Sat Dec 15 19:29:31.000 2012 (UTC + 4:00)
System Uptime: not available
Process Uptime: not available
......................
This dump file has an exception of interest stored in it.
The stored exception information can be accessed via .ecxr.
(8d8.1084): Access violation - code c0000005 (first/second chance not available)
eax=fffffffd ebx=005d0d78 ecx=0022f070 edx=778964f4 esi=005d0d38 edi=0022f110
eip=778964f4 esp=0022edd0 ebp=0022ede0 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
ntdll!KiFastSystemCallRet:
778964f4 c3 ret
0:000> .ecxr
eax=00000000 ebx=7ffdf000 ecx=0022fa30 edx=778964f4 esi=0022fcf4 edi=0022fdcc
eip=0124157c esp=0022fcf4 ebp=0022fdcc iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010246
*** WARNING: Unable to verify checksum for dump.exe
dump!wmain+0x3c:
0124157c c70001000000 mov dword ptr [eax],1 ds:0023:00000000=????????
0:000> dv
argc = 0n1
argv = 0x00280e38
p = 0x00000000
0:000> kb
*** Stack trace for last set context - .thread/.cxr resets it
ChildEBP RetAddr Args to Child
0022fdcc 01241b19 00000001 00280e38 0027f9c8 dump!wmain+0x3c [d:\documents\visual studio 2012\projects\test\dump\dump.cpp # 35]
0022fe1c 01241d0d 0022fe30 76051194 7ffdf000 dump!__tmainCRTStartup+0x199 [f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c # 533]
0022fe24 76051194 7ffdf000 0022fe70 778ab495 dump!wmainCRTStartup+0xd [f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c # 377]
0022fe30 778ab495 7ffdf000 7676831a 00000000 kernel32!BaseThreadInitThunk+0xe
0022fe70 778ab468 0124107d 7ffdf000 00000000 ntdll!__RtlUserThreadStart+0x70
0022fe88 00000000 0124107d 7ffdf000 00000000 ntdll!_RtlUserThreadStart+0x1b
0:000> u .
dump!wmain+0x3c [d:\documents\visual studio 2012\projects\test\dump\dump.cpp # 35]:
0124157c c70001000000 mov dword ptr [eax],1
01241582 33c0 xor eax,eax
01241584 5f pop edi
01241585 5e pop esi
01241586 5b pop ebx
01241587 81c4cc000000 add esp,0CCh
0124158d 3bec cmp ebp,esp
0124158f e8c0fbffff call dump!ILT+335(__RTC_CheckEsp) (01241154)
0:000> !analyze -v
*******************************************************************************
* *
* Exception Analysis *
* *
*******************************************************************************
GetPageUrlData failed, server returned HTTP status 404
URL requested: http://watson.microsoft.com/StageOne/dump_exe/0_0_0_0/50cc9743/dump_exe/0_0_0_0/50cc9743/c0000005/0001157c.htm?Retriage=1
FAULTING_IP:
dump!wmain+3c [d:\documents\visual studio 2012\projects\test\dump\dump.cpp # 35]
0124157c c70001000000 mov dword ptr [eax],1
EXCEPTION_RECORD: ffffffff -- (.exr 0xffffffffffffffff)
ExceptionAddress: 0124157c (dump!wmain+0x0000003c)
ExceptionCode: c0000005 (Access violation)
ExceptionFlags: 00000000
NumberParameters: 2
Parameter[0]: 00000001
Parameter[1]: 00000000
Attempt to write to address 00000000
DEFAULT_BUCKET_ID: NULL_POINTER_WRITE
PROCESS_NAME: dump.exe
ERROR_CODE: (NTSTATUS) 0xc0000005 - The instruction at 0x%08lx referenced memory at 0x%08lx. The memory could not be %s.
EXCEPTION_CODE: (NTSTATUS) 0xc0000005 - The instruction at 0x%08lx referenced memory at 0x%08lx. The memory could not be %s.
EXCEPTION_PARAMETER1: 00000001
EXCEPTION_PARAMETER2: 00000000
WRITE_ADDRESS: 00000000
FOLLOWUP_IP:
dump!wmain+3c [d:\documents\visual studio 2012\projects\test\dump\dump.cpp # 35]
0124157c c70001000000 mov dword ptr [eax],1
MOD_LIST: <ANALYSIS/>
FAULTING_THREAD: 00001084
PRIMARY_PROBLEM_CLASS: NULL_POINTER_WRITE
BUGCHECK_STR: APPLICATION_FAULT_NULL_POINTER_WRITE
LAST_CONTROL_TRANSFER: from 01241b19 to 0124157c
STACK_TEXT:
0022fdcc 01241b19 00000001 00280e38 0027f9c8 dump!wmain+0x3c [d:\documents\visual studio 2012\projects\test\dump\dump.cpp # 35]
0022fe1c 01241d0d 0022fe30 76051194 7ffdf000 dump!__tmainCRTStartup+0x199 [f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c # 533]
0022fe24 76051194 7ffdf000 0022fe70 778ab495 dump!wmainCRTStartup+0xd [f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c # 377]
0022fe30 778ab495 7ffdf000 7676831a 00000000 kernel32!BaseThreadInitThunk+0xe
0022fe70 778ab468 0124107d 7ffdf000 00000000 ntdll!__RtlUserThreadStart+0x70
0022fe88 00000000 0124107d 7ffdf000 00000000 ntdll!_RtlUserThreadStart+0x1b
STACK_COMMAND: ~0s; .ecxr ; kb
FAULTING_SOURCE_CODE:
31: int _tmain(int argc, _TCHAR* argv[])
32: {
33: SetUnhandledExceptionFilter(MyUnhandledExceptionFilter);
34: int* p = NULL;
> 35: *p = 1;
36: return 0;
37: }
38:
SYMBOL_STACK_INDEX: 0
SYMBOL_NAME: dump!wmain+3c
FOLLOWUP_NAME: MachineOwner
MODULE_NAME: dump
IMAGE_NAME: dump.exe
DEBUG_FLR_IMAGE_TIMESTAMP: 50cc9743
FAILURE_BUCKET_ID: NULL_POINTER_WRITE_c0000005_dump.exe!wmain
BUCKET_ID: APPLICATION_FAULT_NULL_POINTER_WRITE_dump!wmain+3c
WATSON_STAGEONE_URL: http://watson.microsoft.com/StageOne/dump_exe/0_0_0_0/50cc9743/dump_exe/0_0_0_0/50cc9743/c0000005/0001157c.htm?Retriage=1
Followup: MachineOwner
---------
Try using AddVectoredExceptionHandler. The thread context of the moment of exception is passed as an argument to the callback proc of this method.
To keep the exception context intact you can create the minidump from an outer process, which debugs the process of interest with DebugActiveProcess API and receives exception events as a part of debugging. Minidump creation preceding release of the debugee with ContinueDebugEvent preserves call stack and exception context.