Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoreutarass2011-02-08 19:35:40 +0000
committereutarass2011-02-08 19:35:40 +0000
commitafea90d60a38824cfbc269414665646812977511 (patch)
tree9e222c97a274b572a5426e639d34068d12833087
parentcf5162334b38786bed6e5fdf76575ed9f6604f93 (diff)
downloadorg.eclipse.tcf.agent-afea90d60a38824cfbc269414665646812977511.tar.gz
org.eclipse.tcf.agent-afea90d60a38824cfbc269414665646812977511.tar.xz
org.eclipse.tcf.agent-afea90d60a38824cfbc269414665646812977511.zip
Bug 336474: [cdt] Add support for C/C++ Watchpoints
-rw-r--r--services/breakpoints.c61
-rw-r--r--services/diagnostics.c4
-rw-r--r--services/expressions.c17
-rw-r--r--services/expressions.h11
-rw-r--r--services/symbols.c9
-rw-r--r--services/symbols.h4
-rw-r--r--services/symbols_elf.c4
-rw-r--r--services/symbols_proxy.c7
-rw-r--r--services/symbols_win32.c27
9 files changed, 86 insertions, 58 deletions
diff --git a/services/breakpoints.c b/services/breakpoints.c
index a1fc558d..05a785a1 100644
--- a/services/breakpoints.c
+++ b/services/breakpoints.c
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2007, 2010 Wind River Systems, Inc. and others.
+ * Copyright (c) 2007, 2011 Wind River Systems, Inc. and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
@@ -945,41 +945,50 @@ static void expr_cache_exit(EvaluationArgs * args) {
run_ctrl_unlock();
}
-static void evaluate_address_expression(void * x) {
- EvaluationArgs * args = (EvaluationArgs *)x;
- BreakpointInfo * bp = args->bp;
+static void plant_at_address_expression(Context * ctx, ContextAddress ip, BreakpointInfo * bp) {
ContextAddress addr = 0;
ContextAddress size = 1;
int error = 0;
Value v;
- assert(cache_enter_cnt > 0);
- if (evaluate_expression(args->ctx, STACK_NO_FRAME, bp->address, 1, &v) < 0) error = errno;
+ if (evaluate_expression(ctx, STACK_NO_FRAME, ip, bp->address, 1, &v) < 0) error = errno;
if (!error && value_to_address(&v, &addr) < 0) error = errno;
if (bp->access_mode & (CTX_BP_ACCESS_DATA_READ | CTX_BP_ACCESS_DATA_WRITE)) {
- Symbol * type = v.type;
- if (type != NULL) {
- int type_class = 0;
- Symbol * base_type = NULL;
- if (!error && get_symbol_type_class(type, &type_class) < 0) error = errno;
- if (!error && type_class != TYPE_CLASS_POINTER) error = set_errno(ERR_INV_DATA_TYPE, "Pointer expected");
- if (!error && get_symbol_base_type(type, &base_type) < 0) error = errno;
- if (!error && base_type != NULL && get_symbol_size(base_type, &size) < 0) error = errno;
- }
- else {
- size = context_word_size(args->ctx);
+ size = context_word_size(ctx);
+#if ENABLE_Symbols
+ {
+ Symbol * type = v.type;
+ if (type != NULL) {
+ int type_class = 0;
+ Symbol * base_type = NULL;
+ if (!error && get_symbol_type_class(type, &type_class) < 0) error = errno;
+ if (!error && type_class != TYPE_CLASS_POINTER) error = set_errno(ERR_INV_DATA_TYPE, "Pointer expected");
+ if (!error && get_symbol_base_type(type, &base_type) < 0) error = errno;
+ if (!error && base_type != NULL && get_symbol_size(base_type, &size) < 0) error = errno;
+ }
}
+#endif
}
- if (error) address_expression_error(args->ctx, bp, error);
- else plant_breakpoint(args->ctx, bp, addr, size);
+ if (error) address_expression_error(ctx, bp, error);
+ else plant_breakpoint(ctx, bp, addr, size);
+}
+
+static void evaluate_address_expression(void * x) {
+ EvaluationArgs * args = (EvaluationArgs *)x;
+ assert(cache_enter_cnt > 0);
+ plant_at_address_expression(args->ctx, 0, args->bp);
expr_cache_exit(args);
}
#if ENABLE_LineNumbers
static void plant_breakpoint_address_iterator(CodeArea * area, void * x) {
EvaluationArgs * args = (EvaluationArgs *)x;
- BreakpointInfo * bp = args->bp;
- plant_breakpoint(args->ctx, bp, area->start_address, 1);
+ if (args->bp->address == NULL) {
+ plant_breakpoint(args->ctx, args->bp, area->start_address, 1);
+ }
+ else {
+ plant_at_address_expression(args->ctx, area->start_address, args->bp);
+ }
}
static void evaluate_text_location(void * x) {
@@ -1029,7 +1038,7 @@ static void evaluate_condition(void * x) {
if (bp->condition != NULL) {
Value v;
int b = 0;
- if (evaluate_expression(ctx, STACK_TOP_FRAME, bp->condition, 1, &v) < 0 || value_to_boolean(&v, &b) < 0) {
+ if (evaluate_expression(ctx, STACK_TOP_FRAME, 0, bp->condition, 1, &v) < 0 || value_to_boolean(&v, &b) < 0) {
int no = get_error_code(errno);
if (no == ERR_CACHE_MISS) continue;
if (no == ERR_CHANNEL_CLOSED) continue;
@@ -1076,10 +1085,7 @@ static void event_replant_breakpoints(void * arg) {
l = l->next;
if (is_disabled(bp)) continue;
if (!check_context_ids(bp, ctx)) continue;
- if (bp->address != NULL) {
- expr_cache_enter(evaluate_address_expression, bp, ctx);
- }
- else if (bp->file != NULL) {
+ if (bp->file != NULL) {
#if ENABLE_LineNumbers
expr_cache_enter(evaluate_text_location, bp, ctx);
#else
@@ -1087,6 +1093,9 @@ static void event_replant_breakpoints(void * arg) {
address_expression_error(NULL, bp, errno);
#endif
}
+ else if (bp->address != NULL) {
+ expr_cache_enter(evaluate_address_expression, bp, ctx);
+ }
else {
address_expression_error(NULL, bp, ERR_INV_EXPRESSION);
}
diff --git a/services/diagnostics.c b/services/diagnostics.c
index 76b0bd90..ae5d316d 100644
--- a/services/diagnostics.c
+++ b/services/diagnostics.c
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2007, 2010 Wind River Systems, Inc. and others.
+ * Copyright (c) 2007, 2011 Wind River Systems, Inc. and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
@@ -251,7 +251,7 @@ static void get_symbol_cache_client(void * x) {
if (ctx->exited) {
error = ERR_ALREADY_EXITED;
}
- else if (find_symbol_by_name(ctx, STACK_NO_FRAME, args->name, &sym) < 0) {
+ else if (find_symbol_by_name(ctx, STACK_NO_FRAME, 0, args->name, &sym) < 0) {
error = errno;
}
else if (get_symbol_address(sym, &addr) < 0) {
diff --git a/services/expressions.c b/services/expressions.c
index d138715a..488452db 100644
--- a/services/expressions.c
+++ b/services/expressions.c
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2007, 2010 Wind River Systems, Inc. and others.
+ * Copyright (c) 2007, 2011 Wind River Systems, Inc. and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
@@ -86,6 +86,7 @@ static StringValue * str_alloc_list = NULL;
static Context * expression_context = NULL;
static int expression_frame = STACK_NO_FRAME;
+static ContextAddress expression_addr = 0;
#define MAX_ID_CALLBACKS 8
static ExpressionIdentifierCallBack * id_callbacks[MAX_ID_CALLBACKS];
@@ -547,7 +548,7 @@ static int identifier(char * name, Value * v) {
#if ENABLE_Symbols
{
Symbol * sym = NULL;
- if (find_symbol_by_name(expression_context, expression_frame, name, &sym) < 0) {
+ if (find_symbol_by_name(expression_context, expression_frame, expression_addr, name, &sym) < 0) {
if (get_error_code(errno) != ERR_SYM_NOT_FOUND) error(errno, "Cannot read symbol data");
}
else {
@@ -1777,11 +1778,12 @@ static void expression(int mode, Value * v) {
conditional_expression(mode, v);
}
-static int evaluate_type(Context * ctx, int frame, char * s, Value * v) {
+static int evaluate_type(Context * ctx, int frame, ContextAddress addr, char * s, Value * v) {
Trap trap;
expression_context = ctx;
expression_frame = frame;
+ expression_addr = addr;
if (!set_trap(&trap)) return -1;
str_pool_cnt = 0;
while (str_alloc_list != NULL) {
@@ -1800,11 +1802,12 @@ static int evaluate_type(Context * ctx, int frame, char * s, Value * v) {
return 0;
}
-int evaluate_expression(Context * ctx, int frame, char * s, int load, Value * v) {
+int evaluate_expression(Context * ctx, int frame, ContextAddress addr, char * s, int load, Value * v) {
Trap trap;
expression_context = ctx;
expression_frame = frame;
+ expression_addr = addr;
if (!set_trap(&trap)) return -1;
if (s == NULL || *s == 0) str_exception(ERR_INV_EXPRESSION, "Empty expression");
str_pool_cnt = 0;
@@ -2201,7 +2204,7 @@ static void command_create_cache_client(void * x) {
else if (id2frame(e->parent, &ctx, &frame) < 0) {
err = errno;
}
- if (!err && evaluate_type(ctx, frame, e->script, &value) < 0) err = errno;
+ if (!err && evaluate_type(ctx, frame, 0, e->script, &value) < 0) err = errno;
if (!err) {
e->can_assign = value.remote;
e->type_class = value.type_class;
@@ -2260,7 +2263,7 @@ static void command_evaluate_cache_client(void * x) {
memset(&value, 0, sizeof(value));
if (expression_context_id(args->id, &ctx, &frame, &expr) < 0) err = errno;
if (!err && frame != STACK_NO_FRAME && !ctx->stopped) err = ERR_IS_RUNNING;
- if (!err && evaluate_expression(ctx, frame, expr->script, 0, &value) < 0) err = errno;
+ if (!err && evaluate_expression(ctx, frame, 0, expr->script, 0, &value) < 0) err = errno;
if (value.size >= 0x100000) err = ERR_BUFFER_OVERFLOW;
cache_exit();
@@ -2346,7 +2349,7 @@ static void command_assign_cache_client(void * x) {
memset(&value, 0, sizeof(value));
if (expression_context_id(args->id, &ctx, &frame, &expr) < 0) err = errno;
if (!err && frame != STACK_NO_FRAME && !ctx->stopped) err = ERR_IS_RUNNING;
- if (!err && evaluate_expression(ctx, frame, expr->script, 0, &value) < 0) err = errno;
+ if (!err && evaluate_expression(ctx, frame, 0, expr->script, 0, &value) < 0) err = errno;
if (!err && !value.remote) err = ERR_INV_EXPRESSION;
if (!err && context_write_mem(ctx, value.address, args->value_buf, args->value_size) < 0) err = errno;
diff --git a/services/expressions.h b/services/expressions.h
index dbf0fc35..a88b9d19 100644
--- a/services/expressions.h
+++ b/services/expressions.h
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2007, 2010 Wind River Systems, Inc. and others.
+ * Copyright (c) 2007, 2011 Wind River Systems, Inc. and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
@@ -47,10 +47,15 @@ typedef int ExpressionIdentifierCallBack(Context *, int /*frame*/, char * /*name
/*
* Evaluate given expression in given context.
- * If load != 0 then result value is always loaded into a local buffer.
+ * 'ctx' - debug context to use for memory access and symbols lookup.
+ * 'frame' - stack frame to use for registers and local variables values.
+ * 'addr' - instruction address for symbols lookup, ignored if frame != STACK_NO_FRAME.
+ * 's' - the expression text.
+ * If load != 0 then result value is always loaded into a local buffer,
+ * otherwise 'v' can point to a value in the target memory.
* Return 0 if no errors, otherwise return -1 and sets errno.
*/
-extern int evaluate_expression(Context * ctx, int frame, char * s, int load, Value * v);
+extern int evaluate_expression(Context * ctx, int frame, ContextAddress addr, char * s, int load, Value * v);
/*
* Cast a Value to a boolean - 0 or 1.
diff --git a/services/symbols.c b/services/symbols.c
index 172b06ce..ab0f1166 100644
--- a/services/symbols.c
+++ b/services/symbols.c
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2007, 2010 Wind River Systems, Inc. and others.
+ * Copyright (c) 2007, 2011 Wind River Systems, Inc. and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
@@ -271,6 +271,7 @@ static void command_get_children(char * token, Channel * c) {
typedef struct CommandFindByNameArgs {
char token[256];
char id[256];
+ ContextAddress ip;
char * name;
} CommandFindByNameArgs;
@@ -286,7 +287,7 @@ static void command_find_by_name_cache_client(void * x) {
if (ctx == NULL) err = set_errno(ERR_INV_CONTEXT, args->id);
else if (ctx->exited) err = ERR_ALREADY_EXITED;
- if (err == 0 && find_symbol_by_name(ctx, frame, args->name, &sym) < 0) err = errno;
+ if (err == 0 && find_symbol_by_name(ctx, frame, args->ip, args->name, &sym) < 0) err = errno;
cache_exit();
@@ -311,6 +312,10 @@ static void command_find_by_name(char * token, Channel * c) {
json_read_string(&c->inp, args.id, sizeof(args.id));
if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX);
+ if (peek_stream(&c->inp) != '"' && peek_stream(&c->inp) != 'n') {
+ args.ip = (ContextAddress)json_read_uint64(&c->inp);
+ if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX);
+ }
args.name = json_read_alloc_string(&c->inp);
if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX);
if (read_stream(&c->inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX);
diff --git a/services/symbols.h b/services/symbols.h
index ccb75a56..2fbc8b6f 100644
--- a/services/symbols.h
+++ b/services/symbols.h
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2007, 2010 Wind River Systems, Inc. and others.
+ * Copyright (c) 2007, 2011 Wind River Systems, Inc. and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
@@ -59,7 +59,7 @@ typedef void EnumerateSymbolsCallBack(void *, Symbol *);
* On error, returns -1 and sets errno.
* On success returns 0.
*/
-extern int find_symbol_by_name(Context * ctx, int frame, char * name, Symbol ** sym);
+extern int find_symbol_by_name(Context * ctx, int frame, ContextAddress ip, char * name, Symbol ** sym);
/*
* Find symbol information for given address in given context.
diff --git a/services/symbols_elf.c b/services/symbols_elf.c
index 3bfb40e9..f4851bf0 100644
--- a/services/symbols_elf.c
+++ b/services/symbols_elf.c
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2007, 2010 Wind River Systems, Inc. and others.
+ * Copyright (c) 2007, 2011 Wind River Systems, Inc. and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
@@ -330,7 +330,7 @@ static int find_by_name_in_sym_table(DWARFCache * cache, char * name, Symbol **
return cnt == 1;
}
-int find_symbol_by_name(Context * ctx, int frame, char * name, Symbol ** res) {
+int find_symbol_by_name(Context * ctx, int frame, ContextAddress ip, char * name, Symbol ** res) {
int error = 0;
int found = 0;
diff --git a/services/symbols_proxy.c b/services/symbols_proxy.c
index 98f9e967..51b8cf75 100644
--- a/services/symbols_proxy.c
+++ b/services/symbols_proxy.c
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2007, 2010 Wind River Systems, Inc. and others.
+ * Copyright (c) 2007, 2011 Wind River Systems, Inc. and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
@@ -430,7 +430,7 @@ static void validate_find(Channel * c, void * args, int error) {
if (trap.error) exception(trap.error);
}
-int find_symbol_by_name(Context * ctx, int frame, char * name, Symbol ** sym) {
+int find_symbol_by_name(Context * ctx, int frame, ContextAddress addr, char * name, Symbol ** sym) {
uint64_t ip = 0;
LINK * l = NULL;
SymbolsCache * syms = NULL;
@@ -442,6 +442,7 @@ int find_symbol_by_name(Context * ctx, int frame, char * name, Symbol ** sym) {
if (frame == STACK_NO_FRAME) {
ctx = context_get_group(ctx, CONTEXT_GROUP_PROCESS);
+ ip = addr;
}
else {
StackFrame * info = NULL;
@@ -503,6 +504,8 @@ int find_symbol_by_name(Context * ctx, int frame, char * name, Symbol ** sym) {
json_write_string(&c->out, ctx->id);
}
write_stream(&c->out, 0);
+ json_write_uint64(&c->out, ip);
+ write_stream(&c->out, 0);
json_write_string(&c->out, name);
write_stream(&c->out, 0);
write_stream(&c->out, MARKER_EOM);
diff --git a/services/symbols_win32.c b/services/symbols_win32.c
index 864323e7..aa7df58f 100644
--- a/services/symbols_win32.c
+++ b/services/symbols_win32.c
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2007, 2010 Wind River Systems, Inc. and others.
+ * Copyright (c) 2007, 2011 Wind River Systems, Inc. and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
@@ -116,9 +116,12 @@ static SymbolCacheEntry symbol_cache[SYMBOL_CACHE_SIZE];
static char * tmp_buf = NULL;
static int tmp_buf_size = 0;
-static int get_stack_frame(Context * ctx, int frame, IMAGEHLP_STACK_FRAME * stack_frame) {
+static int get_stack_frame(Context * ctx, int frame, ContextAddress ip, IMAGEHLP_STACK_FRAME * stack_frame) {
memset(stack_frame, 0, sizeof(IMAGEHLP_STACK_FRAME));
- if (frame != STACK_NO_FRAME && ctx->parent != NULL) {
+ if (frame == STACK_NO_FRAME) {
+ stack_frame->InstructionOffset = ip;
+ }
+ else if (ctx->parent != NULL) {
uint64_t v = 0;
StackFrame * frame_info;
if (get_frame_info(ctx, frame, &frame_info) < 0) return -1;
@@ -806,8 +809,8 @@ static void add_cache_symbol(HANDLE process, ULONG64 pc, PCSTR name, Symbol * sy
}
}
-static int set_pe_context(Context * ctx, int frame, HANDLE process, IMAGEHLP_STACK_FRAME * stack_frame) {
- if (get_stack_frame(ctx, frame, stack_frame) < 0) return -1;
+static int set_pe_context(Context * ctx, int frame, ContextAddress ip, HANDLE process, IMAGEHLP_STACK_FRAME * stack_frame) {
+ if (get_stack_frame(ctx, frame, ip, stack_frame) < 0) return -1;
if (!SymSetContext(process, stack_frame, NULL)) {
DWORD err = GetLastError();
@@ -816,7 +819,7 @@ static int set_pe_context(Context * ctx, int frame, HANDLE process, IMAGEHLP_STA
}
else if (err == ERROR_MOD_NOT_FOUND && frame != STACK_NO_FRAME) {
/* No local symbols data, search global scope */
- if (get_stack_frame(ctx, STACK_NO_FRAME, stack_frame) < 0) return -1;
+ if (get_stack_frame(ctx, STACK_NO_FRAME, 0, stack_frame) < 0) return -1;
if (!SymSetContext(process, stack_frame, NULL)) {
err = GetLastError();
if (err != ERROR_SUCCESS) {
@@ -838,14 +841,14 @@ static int set_pe_context(Context * ctx, int frame, HANDLE process, IMAGEHLP_STA
return 0;
}
-static int find_pe_symbol_by_name(Context * ctx, int frame, char * name, Symbol * sym) {
+static int find_pe_symbol_by_name(Context * ctx, int frame, ContextAddress ip, char * name, Symbol * sym) {
HANDLE process = get_context_handle(ctx->parent == NULL ? ctx : ctx->parent);
ULONG64 buffer[(sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR) + sizeof(ULONG64) - 1) / sizeof(ULONG64)];
SYMBOL_INFO * info = (SYMBOL_INFO *)buffer;
IMAGEHLP_STACK_FRAME stack_frame;
DWORD err;
- if (set_pe_context(ctx, frame, process, &stack_frame) < 0) return -1;
+ if (set_pe_context(ctx, frame, ip, process, &stack_frame) < 0) return -1;
memset(info, 0, sizeof(SYMBOL_INFO));
info->SizeOfStruct = sizeof(SYMBOL_INFO);
@@ -882,7 +885,7 @@ static int find_pe_symbol_by_addr(Context * ctx, int frame, ContextAddress addr,
IMAGEHLP_STACK_FRAME stack_frame;
DWORD err;
- if (set_pe_context(ctx, frame, process, &stack_frame) < 0) return -1;
+ if (set_pe_context(ctx, frame, 0, process, &stack_frame) < 0) return -1;
memset(info, 0, sizeof(SYMBOL_INFO));
info->SizeOfStruct = sizeof(SYMBOL_INFO);
@@ -915,12 +918,12 @@ static int find_basic_type_symbol(Context * ctx, char * name, Symbol * sym) {
return -1;
}
-int find_symbol_by_name(Context * ctx, int frame, char * name, Symbol ** sym) {
+int find_symbol_by_name(Context * ctx, int frame, ContextAddress ip, char * name, Symbol ** sym) {
int found = 0;
*sym = alloc_symbol();
(*sym)->ctx = ctx;
if (frame == STACK_TOP_FRAME && (frame = get_top_frame(ctx)) < 0) return -1;
- if (find_pe_symbol_by_name(ctx, frame, name, *sym) >= 0) found = 1;
+ if (find_pe_symbol_by_name(ctx, frame, ip, name, *sym) >= 0) found = 1;
else if (get_error_code(errno) != ERR_SYM_NOT_FOUND) return -1;
#if ENABLE_RCBP_TEST
if (!found) {
@@ -987,7 +990,7 @@ int enumerate_symbols(Context * ctx, int frame, EnumerateSymbolsCallBack * call_
if (frame == STACK_TOP_FRAME) frame = get_top_frame(ctx);
if (frame == STACK_TOP_FRAME) return -1;
- if (get_stack_frame(ctx, frame, &stack_frame) < 0) return -1;
+ if (get_stack_frame(ctx, frame, 0, &stack_frame) < 0) return -1;
if (!SymSetContext(process, &stack_frame, NULL)) {
DWORD err = GetLastError();

Back to the top