Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'agent/tcf/services/linenumbers_win32.c')
-rw-r--r--agent/tcf/services/linenumbers_win32.c207
1 files changed, 207 insertions, 0 deletions
diff --git a/agent/tcf/services/linenumbers_win32.c b/agent/tcf/services/linenumbers_win32.c
new file mode 100644
index 00000000..60b58747
--- /dev/null
+++ b/agent/tcf/services/linenumbers_win32.c
@@ -0,0 +1,207 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2010 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.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+
+/*
+ * TCF service line Numbers
+ * The service associates locations in the source files with the corresponding
+ * machine instruction addresses in the executable object.
+ */
+
+#include <config.h>
+
+#if SERVICE_LineNumbers && !ENABLE_LineNumbersProxy && defined(WIN32) && !ENABLE_ELF
+
+#include <errno.h>
+#include <assert.h>
+#include <stdio.h>
+#include <framework/json.h>
+#include <framework/protocol.h>
+#include <framework/context.h>
+#include <framework/exceptions.h>
+#include <services/linenumbers.h>
+#include <system/Windows/windbgcache.h>
+#include <system/Windows/context-win32.h>
+
+int line_to_address(Context * ctx, char * file, int line, int column,
+ LineNumbersCallBack * callback, void * user_args) {
+ int err = 0;
+
+ if (ctx == NULL) err = ERR_INV_CONTEXT;
+ else if (ctx->exited) err = ERR_ALREADY_EXITED;
+
+ if (err == 0 && ctx->parent != NULL) ctx = ctx->parent;
+
+ if (err == 0) {
+ LONG offset = 0;
+ IMAGEHLP_LINE img_line;
+ CodeArea area;
+ memset(&img_line, 0, sizeof(img_line));
+ memset(&area, 0, sizeof(area));
+ img_line.SizeOfStruct = sizeof(IMAGEHLP_LINE);
+
+ if (!SymGetLineFromName(get_context_handle(ctx), NULL, file, line, &offset, &img_line)) {
+ DWORD win_err = GetLastError();
+ if (win_err != ERROR_NOT_FOUND) {
+ err = set_win32_errno(win_err);
+ }
+ }
+ else {
+ IMAGEHLP_LINE img_next;
+ memcpy(&img_next, &img_line, sizeof(img_next));
+ if (!SymGetLineNext(get_context_handle(ctx), &img_next)) {
+ err = set_win32_errno(GetLastError());
+ }
+ else {
+ area.file = img_line.FileName;
+ area.start_line = img_line.LineNumber;
+ area.start_address = img_line.Address;
+ area.end_line = img_next.LineNumber;
+ area.end_address = img_next.Address;
+ callback(&area, user_args);
+ }
+ }
+ }
+
+ if (err != 0) {
+ errno = err;
+ return -1;
+ }
+ return 0;
+}
+
+#define JMPD08 0xeb
+#define JMPD32 0xe9
+#define GRP5 0xff
+#define JMPN 0x25
+
+int address_to_line(Context * ctx, ContextAddress addr0, ContextAddress addr1, LineNumbersCallBack * callback, void * user_args) {
+ int err = 0;
+ int not_found = 0;
+ DWORD offset = 0;
+ IMAGEHLP_LINE line;
+ IMAGEHLP_LINE next;
+ ContextAddress org_addr0 = addr0;
+ ContextAddress org_addr1 = addr1;
+
+ if (ctx == NULL) err = ERR_INV_CONTEXT;
+ else if (ctx->exited) err = ERR_ALREADY_EXITED;
+
+ if (err == 0 && ctx->parent != NULL) ctx = ctx->parent;
+
+ memset(&line, 0, sizeof(line));
+ line.SizeOfStruct = sizeof(IMAGEHLP_LINE);
+ if (addr0 >= addr1) not_found = 1;
+
+ while (err == 0 && not_found == 0 && !SymGetLineFromAddr(get_context_handle(ctx), addr0, &offset, &line)) {
+ DWORD w = GetLastError();
+ if (w == ERROR_MOD_NOT_FOUND) {
+ not_found = 1;
+ }
+ else if (w == ERROR_INVALID_ADDRESS) {
+ /* Check if the address points to a jump instruction (e.g. inside a jump table)
+ * and try to get line info for jump destination address.
+ */
+ unsigned char instr; /* instruction opcode at <addr0> */
+ ContextAddress dest = 0; /* Jump destination address */
+ if (context_read_mem(ctx, addr0, &instr, 1) == 0) {
+ /* If instruction is a JMP, get destination adrs */
+ if (instr == JMPD08) {
+ signed char disp08;
+ if (context_read_mem(ctx, addr0 + 1, &disp08, 1) == 0) {
+ dest = addr0 + 2 + disp08;
+ org_addr1 = addr0 + 2;
+ }
+ }
+ else if (instr == JMPD32) {
+ int disp32;
+ assert(sizeof(disp32) == 4);
+ if (context_read_mem(ctx, addr0 + 1, &disp32, 4) == 0) {
+ dest = addr0 + 5 + disp32;
+ org_addr1 = addr0 + 5;
+ }
+ }
+ else if (instr == GRP5) {
+ if (context_read_mem(ctx, addr0 + 1, &instr, 1) == 0 && instr == JMPN) {
+ ContextAddress ptr = 0;
+ if (context_read_mem(ctx, addr0 + 2, &ptr, 4) == 0) {
+ context_read_mem(ctx, ptr, &dest, 4);
+ org_addr1 = addr0 + 6;
+ }
+ }
+ }
+ }
+ if (dest != 0) {
+ addr0 = dest;
+ addr1 = dest + 1;
+ }
+ else {
+ not_found = 1;
+ }
+ }
+ else {
+ err = set_win32_errno(w);
+ }
+ }
+ memcpy(&next, &line, sizeof(next));
+ if (err == 0 && !not_found && !SymGetLineNext(get_context_handle(ctx), &next)) {
+ DWORD w = GetLastError();
+ if (w == ERROR_NOT_FOUND) {
+ /* Last line in the source file */
+ ULONG64 buffer[(sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR) + sizeof(ULONG64) - 1) / sizeof(ULONG64)];
+ SYMBOL_INFO * info = (SYMBOL_INFO *)buffer;
+ info->SizeOfStruct = sizeof(SYMBOL_INFO);
+ info->MaxNameLen = MAX_SYM_NAME;
+ if (SymFromAddr(get_context_handle(ctx), next.Address, NULL, info)) {
+ next.Address = (ULONG_PTR)info->Address + info->Size;
+ next.LineNumber++;
+ }
+ }
+ else {
+ err = set_win32_errno(GetLastError());
+ }
+ }
+
+ if (err == 0 && !not_found) {
+ while (line.Address < next.Address && line.Address < addr1 && next.Address > addr0) {
+ CodeArea area;
+
+ memset(&area, 0, sizeof(area));
+ area.file = line.FileName;
+ area.start_address = line.Address;
+ area.start_line = line.LineNumber;
+ area.end_address = next.Address;
+ area.end_line = next.LineNumber;
+ if (org_addr0 != addr0) {
+ area.start_address = org_addr0;
+ area.end_address = org_addr1;
+ }
+ callback(&area, user_args);
+ memcpy(&line, &next, sizeof(line));
+ if (!SymGetLineNext(get_context_handle(ctx), &next)) break;
+ }
+ }
+
+ if (err != 0) {
+ errno = err;
+ return -1;
+ }
+ return 0;
+}
+
+void ini_line_numbers_lib(void) {
+ SymSetOptions(SymGetOptions() | SYMOPT_LOAD_LINES | SYMOPT_DEFERRED_LOADS);
+}
+
+#endif /* SERVICE_LineNumbers && !ENABLE_LineNumbersProxy && defined(_MSC_VER) && !ENABLE_ELF */

Back to the top