TCF Server: fixed symbols server support of stepping over inlined functions
diff --git a/agent/tcf/services/linenumbers.c b/agent/tcf/services/linenumbers.c
index 2208d06..b8bf0fa 100644
--- a/agent/tcf/services/linenumbers.c
+++ b/agent/tcf/services/linenumbers.c
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2007, 2013 Wind River Systems, Inc. and others.
+ * Copyright (c) 2007, 2015 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.
@@ -22,7 +22,7 @@
 
 #include <tcf/config.h>
 
-#if SERVICE_LineNumbers
+#if ENABLE_DebugContext
 
 #include <errno.h>
 #include <assert.h>
@@ -36,33 +36,32 @@
 #include <tcf/framework/trace.h>
 #include <tcf/services/linenumbers.h>
 
-#define MAX_AREA_CNT 0x1000
+static void read_code_area_props(InputStream * inp, const char * name, void * args) {
+    CodeArea * area = (CodeArea *)args;
+    if (strcmp(name, "SLine") == 0) area->start_line = json_read_long(inp);
+    else if (strcmp(name, "SCol") == 0) area->start_column = json_read_long(inp);
+    else if (strcmp(name, "SAddr") == 0) area->start_address = (ContextAddress)json_read_uint64(inp);
+    else if (strcmp(name, "ELine") == 0) area->end_line = json_read_long(inp);
+    else if (strcmp(name, "ECol") == 0) area->end_column = json_read_long(inp);
+    else if (strcmp(name, "EAddr") == 0) area->end_address = (ContextAddress)json_read_uint64(inp);
+    else if (strcmp(name, "NAddr") == 0) area->next_address = (ContextAddress)json_read_uint64(inp);
+    else if (strcmp(name, "File") == 0) area->file = json_read_alloc_string(inp);
+    else if (strcmp(name, "Dir") == 0) area->directory = json_read_alloc_string(inp);
+    else if (strcmp(name, "ISA") == 0) area->isa = json_read_long(inp);
+    else if (strcmp(name, "IsStmt") == 0) area->is_statement = json_read_boolean(inp);
+    else if (strcmp(name, "BasicBlock") == 0) area->basic_block = json_read_boolean(inp);
+    else if (strcmp(name, "PrologueEnd") == 0) area->prologue_end = json_read_boolean(inp);
+    else if (strcmp(name, "EpilogueBegin") == 0) area->epilogue_begin = json_read_boolean(inp);
+    else if (strcmp(name, "OpIndex") == 0) area->op_index = json_read_long(inp);
+    else if (strcmp(name, "Discriminator") == 0) area->discriminator = json_read_long(inp);
+}
 
-typedef struct MapToSourceArgs {
-    char token[256];
-    char id[256];
-    ContextAddress addr0;
-    ContextAddress addr1;
-} MapToSourceArgs;
+void read_code_area(InputStream * inp, CodeArea * area) {
+    memset(area, 0, sizeof(CodeArea));
+    json_read_struct(inp, read_code_area_props, area);
+}
 
-typedef struct MapToMemoryArgs {
-    char token[256];
-    char id[256];
-    char * file;
-    int line;
-    int column;
-} MapToMemoryArgs;
-
-static int code_area_cnt = 0;
-static int code_area_max = 0;
-static CodeArea * code_area_buf = NULL;
-
-static const char * LINENUMBERS = "LineNumbers";
-
-static void write_line_info(OutputStream * out, int cnt) {
-    CodeArea * area = code_area_buf + cnt;
-    CodeArea * prev = cnt == 0 ? NULL : code_area_buf + cnt - 1;
-
+void write_code_area(OutputStream * out, CodeArea * area, CodeArea * prev) {
     write_stream(out, '{');
     json_write_string(out, "SAddr");
     write_stream(out, ':');
@@ -160,6 +159,38 @@
     write_stream(out, '}');
 }
 
+#if SERVICE_LineNumbers
+
+#define MAX_AREA_CNT 0x1000
+
+typedef struct MapToSourceArgs {
+    char token[256];
+    char id[256];
+    ContextAddress addr0;
+    ContextAddress addr1;
+} MapToSourceArgs;
+
+typedef struct MapToMemoryArgs {
+    char token[256];
+    char id[256];
+    char * file;
+    int line;
+    int column;
+} MapToMemoryArgs;
+
+static int code_area_cnt = 0;
+static int code_area_max = 0;
+static CodeArea * code_area_buf = NULL;
+
+static const char * LINENUMBERS = "LineNumbers";
+
+static void write_line_info(OutputStream * out, int cnt) {
+    CodeArea * area = code_area_buf + cnt;
+    CodeArea * prev = cnt == 0 ? NULL : code_area_buf + cnt - 1;
+    write_code_area(out, area, prev);
+}
+
+
 static void add_code_area(CodeArea * area, void * args) {
     if (code_area_cnt >= code_area_max) {
         if (code_area_max >= MAX_AREA_CNT) exception(ERR_BUFFER_OVERFLOW);
@@ -287,3 +318,4 @@
 }
 
 #endif /* SERVICE_LineNumbers */
+#endif /* ENABLE_DebugContext */
diff --git a/agent/tcf/services/linenumbers.h b/agent/tcf/services/linenumbers.h
index 1a76c85..788ce15 100644
--- a/agent/tcf/services/linenumbers.h
+++ b/agent/tcf/services/linenumbers.h
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2007, 2014 Wind River Systems, Inc. and others.
+ * Copyright (c) 2007, 2015 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.
@@ -24,6 +24,19 @@
 
 #include <tcf/framework/protocol.h>
 #include <tcf/framework/context.h>
+#include <tcf/framework/cpudefs.h>
+
+#if ENABLE_DebugContext
+
+/*
+ * Utility function: read code area data from JSON stream.
+ */
+extern void read_code_area(InputStream * inp, CodeArea * area);
+
+/*
+ * Utility function: write code area data into JSON stream.
+ */
+extern void write_code_area(OutputStream * out, CodeArea * area, CodeArea * prev);
 
 #if ENABLE_LineNumbers
 
@@ -46,5 +59,6 @@
 extern void ini_line_numbers_lib(void);
 
 #endif /* ENABLE_LineNumbers */
+#endif /* ENABLE_DebugContext */
 
 #endif /* D_linenumbers */
diff --git a/agent/tcf/services/linenumbers_proxy.c b/agent/tcf/services/linenumbers_proxy.c
index f376067..c2115de 100644
--- a/agent/tcf/services/linenumbers_proxy.c
+++ b/agent/tcf/services/linenumbers_proxy.c
@@ -155,26 +155,6 @@
     return (h + ((uintptr_t)ctx >> 4) + (unsigned)line + (unsigned)column) % HASH_SIZE;
 }
 
-static void read_code_area_props(InputStream * inp, const char * name, void * args) {
-    CodeArea * area = (CodeArea *)args;
-    if (strcmp(name, "SLine") == 0) area->start_line = json_read_long(inp);
-    else if (strcmp(name, "SCol") == 0) area->start_column = json_read_long(inp);
-    else if (strcmp(name, "SAddr") == 0) area->start_address = (ContextAddress)json_read_uint64(inp);
-    else if (strcmp(name, "ELine") == 0) area->end_line = json_read_long(inp);
-    else if (strcmp(name, "ECol") == 0) area->end_column = json_read_long(inp);
-    else if (strcmp(name, "EAddr") == 0) area->end_address = (ContextAddress)json_read_uint64(inp);
-    else if (strcmp(name, "NAddr") == 0) area->next_address = (ContextAddress)json_read_uint64(inp);
-    else if (strcmp(name, "File") == 0) area->file = json_read_alloc_string(inp);
-    else if (strcmp(name, "Dir") == 0) area->directory = json_read_alloc_string(inp);
-    else if (strcmp(name, "ISA") == 0) area->isa = json_read_long(inp);
-    else if (strcmp(name, "IsStmt") == 0) area->is_statement = json_read_boolean(inp);
-    else if (strcmp(name, "BasicBlock") == 0) area->basic_block = json_read_boolean(inp);
-    else if (strcmp(name, "PrologueEnd") == 0) area->prologue_end = json_read_boolean(inp);
-    else if (strcmp(name, "EpilogueBegin") == 0) area->epilogue_begin = json_read_boolean(inp);
-    else if (strcmp(name, "OpIndex") == 0) area->op_index = json_read_long(inp);
-    else if (strcmp(name, "Discriminator") == 0) area->discriminator = json_read_long(inp);
-}
-
 static void read_code_area_array(InputStream * inp, void * args) {
     CodeArea * area = NULL;
     if (code_area_cnt >= code_area_max) {
@@ -182,8 +162,7 @@
         code_area_buf = (CodeArea *)loc_realloc(code_area_buf, sizeof(CodeArea) * code_area_max);
     }
     area = code_area_buf + code_area_cnt++;
-    memset(area, 0, sizeof(CodeArea));
-    json_read_struct(inp, read_code_area_props, area);
+    read_code_area(inp, area);
 }
 
 static void validate_cache_entry(Channel * c, void * args, int error) {
diff --git a/agent/tcf/services/stacktrace.c b/agent/tcf/services/stacktrace.c
index b3fb8a1..5aff535 100644
--- a/agent/tcf/services/stacktrace.c
+++ b/agent/tcf/services/stacktrace.c
@@ -34,9 +34,10 @@
 #include <tcf/framework/cache.h>
 #include <tcf/framework/exceptions.h>
 #include <tcf/services/registers.h>
-#include <tcf/services/stacktrace.h>
 #include <tcf/services/symbols.h>
+#include <tcf/services/linenumbers.h>
 #include <tcf/services/memorymap.h>
+#include <tcf/services/stacktrace.h>
 
 #define MAX_FRAMES  1000
 
@@ -95,7 +96,7 @@
                 *down->area = info->subs[down->inlined]->area;
                 if (down->area->directory) down->area->directory = loc_strdup(down->area->directory);
                 if (down->area->file) down->area->file = loc_strdup(down->area->file);
-                frame->func_id = loc_strdup(symbol2id(info->subs[down->inlined]->sym));
+                frame->func_id = loc_strdup(info->subs[down->inlined]->func_id);
             }
             else {
                 int i;
@@ -339,57 +340,10 @@
     }
 
     if (d->info->area != NULL) {
-        CodeArea * area = d->info->area;
         write_stream(out, ',');
         json_write_string(out, "CodeArea");
         write_stream(out, ':');
-        write_stream(out, '{');
-        json_write_string(out, "SAddr");
-        write_stream(out, ':');
-        json_write_uint64(out, area->start_address);
-        if (area->start_line > 0) {
-            write_stream(out, ',');
-            json_write_string(out, "SLine");
-            write_stream(out, ':');
-            json_write_ulong(out, area->start_line);
-            if (area->start_column > 0) {
-                write_stream(out, ',');
-                json_write_string(out, "SCol");
-                write_stream(out, ':');
-                json_write_ulong(out, area->start_column);
-            }
-        }
-        if (area->end_address != 0) {
-            write_stream(out, ',');
-            json_write_string(out, "EAddr");
-            write_stream(out, ':');
-            json_write_uint64(out, area->end_address);
-        }
-        if (area->end_line > 0) {
-            write_stream(out, ',');
-            json_write_string(out, "ELine");
-            write_stream(out, ':');
-            json_write_ulong(out, area->end_line);
-            if (area->end_column > 0) {
-                write_stream(out, ',');
-                json_write_string(out, "ECol");
-                write_stream(out, ':');
-                json_write_ulong(out, area->end_column);
-            }
-        }
-        if (area->file != NULL) {
-            write_stream(out, ',');
-            json_write_string(out, "File");
-            write_stream(out, ':');
-            json_write_string(out, area->file);
-        }
-        if (area->directory != NULL) {
-            write_stream(out, ',');
-            json_write_string(out, "Dir");
-            write_stream(out, ':');
-            json_write_string(out, area->directory);
-        }
-        write_stream(out, '}');
+        write_code_area(out, d->info->area, NULL);
     }
 
     if (d->ip_error == 0) {
diff --git a/agent/tcf/services/symbols.c b/agent/tcf/services/symbols.c
index a4c7c32..df7b978 100644
--- a/agent/tcf/services/symbols.c
+++ b/agent/tcf/services/symbols.c
@@ -26,6 +26,7 @@
 #include <tcf/framework/cache.h>
 #include <tcf/services/stacktrace.h>
 #include <tcf/services/memorymap.h>
+#include <tcf/services/linenumbers.h>
 #include <tcf/services/symbols.h>
 #include <tcf/services/vm.h>
 
@@ -782,6 +783,28 @@
     }
 }
 
+static void write_inlined_subroutine_info(OutputStream * out, StackFrameInlinedSubroutine * info) {
+    unsigned cnt = 0;
+
+    write_stream(out, '{');
+
+    if (info->func_id != NULL) {
+        if (cnt++ > 0) write_stream(out, ',');
+        json_write_string(out, "ID");
+        write_stream(out, ':');
+        json_write_string(out, info->func_id);
+    }
+
+#if ENABLE_LineNumbers
+    if (cnt++ > 0) write_stream(out, ',');
+    json_write_string(out, "Area");
+    write_stream(out, ':');
+    write_code_area(out, &info->area, NULL);
+#endif /* ENABLE_LineNumbers */
+
+    write_stream(out, '}');
+}
+
 typedef struct CommandGetLocationInfo {
     char token[256];
     char id[256];
@@ -881,9 +904,10 @@
     char token[256];
     char id[256];
     ContextAddress addr;
+    int props;
 } CommandFindFrameInfo;
 
-static void command_find_frame_info_cache_client(void * x) {
+static void command_find_frame_props_cache_client(void * x) {
     CommandFindFrameInfo * args = (CommandFindFrameInfo *)x;
     Channel * c = cache_channel();
     Context * ctx = NULL;
@@ -900,30 +924,87 @@
     write_stringz(&c->out, args->token);
     write_errno(&c->out, err);
 
-    json_write_uint64(&c->out, info ? info->addr : 0);
-    write_stream(&c->out, 0);
-    json_write_uint64(&c->out, info ? info->size : 0);
-    write_stream(&c->out, 0);
-
-    if (info == NULL || info->fp == NULL) write_string(&c->out, "null");
-    else write_commands(&c->out, ctx, info->fp->cmds, info->fp->cmds_cnt);
-    write_stream(&c->out, 0);
-
-    if (info != NULL && info->regs != NULL) {
-        int i;
+    if (args->props) {
+        unsigned cnt = 0;
         write_stream(&c->out, '{');
-        for (i = 0; i < info->reg_cnt; i++) {
-            if (i > 0) write_stream(&c->out, ',');
-            json_write_string(&c->out, register2id(ctx, STACK_NO_FRAME, info->regs[i]->reg));
+
+        if (info != NULL && info->size) {
+            json_write_string(&c->out, "CodeAddr");
             write_stream(&c->out, ':');
-            write_commands(&c->out, ctx, info->regs[i]->cmds, info->regs[i]->cmds_cnt);
+            json_write_uint64(&c->out, info->addr);
+            write_stream(&c->out, ',');
+            json_write_string(&c->out, "CodeSize");
+            write_stream(&c->out, ':');
+            json_write_uint64(&c->out, info->size);
+            cnt++;
         }
+
+        if (info != NULL && info->fp != NULL) {
+            if (cnt++ > 0) write_stream(&c->out, ',');
+            json_write_string(&c->out, "FP");
+            write_stream(&c->out, ':');
+            write_commands(&c->out, ctx, info->fp->cmds, info->fp->cmds_cnt);
+        }
+
+        if (info != NULL && info->regs != NULL) {
+            int i;
+            if (cnt++ > 0) write_stream(&c->out, ',');
+            json_write_string(&c->out, "Regs");
+            write_stream(&c->out, ':');
+            write_stream(&c->out, '{');
+            for (i = 0; i < info->reg_cnt; i++) {
+                if (i > 0) write_stream(&c->out, ',');
+                json_write_string(&c->out, register2id(ctx, STACK_NO_FRAME, info->regs[i]->reg));
+                write_stream(&c->out, ':');
+                write_commands(&c->out, ctx, info->regs[i]->cmds, info->regs[i]->cmds_cnt);
+            }
+            write_stream(&c->out, '}');
+        }
+
+        if (info != NULL && info->subs != NULL) {
+            int i;
+            if (cnt++ > 0) write_stream(&c->out, ',');
+            json_write_string(&c->out, "Inlined");
+            write_stream(&c->out, ':');
+            write_stream(&c->out, '[');
+            for (i = 0; i < info->sub_cnt; i++) {
+                if (i > 0) write_stream(&c->out, ',');
+                write_inlined_subroutine_info(&c->out, info->subs[i]);
+            }
+            write_stream(&c->out, ']');
+        }
+
         write_stream(&c->out, '}');
+        write_stream(&c->out, 0);
     }
     else {
-        write_string(&c->out, "null");
+        /* Deprecated, use findFrameProps */
+
+        json_write_uint64(&c->out, info ? info->addr : 0);
+        write_stream(&c->out, 0);
+        json_write_uint64(&c->out, info ? info->size : 0);
+        write_stream(&c->out, 0);
+
+        if (info == NULL || info->fp == NULL) write_string(&c->out, "null");
+        else write_commands(&c->out, ctx, info->fp->cmds, info->fp->cmds_cnt);
+        write_stream(&c->out, 0);
+
+        if (info != NULL && info->regs != NULL) {
+            int i;
+            write_stream(&c->out, '{');
+            for (i = 0; i < info->reg_cnt; i++) {
+                if (i > 0) write_stream(&c->out, ',');
+                json_write_string(&c->out, register2id(ctx, STACK_NO_FRAME, info->regs[i]->reg));
+                write_stream(&c->out, ':');
+                write_commands(&c->out, ctx, info->regs[i]->cmds, info->regs[i]->cmds_cnt);
+            }
+            write_stream(&c->out, '}');
+        }
+        else {
+            write_string(&c->out, "null");
+        }
+        write_stream(&c->out, 0);
     }
-    write_stream(&c->out, 0);
 
     write_stream(&c->out, MARKER_EOM);
 }
@@ -936,9 +1017,24 @@
     args.addr = (ContextAddress)json_read_uint64(&c->inp);
     json_test_char(&c->inp, MARKER_EOA);
     json_test_char(&c->inp, MARKER_EOM);
+    args.props = 0;
 
     strlcpy(args.token, token, sizeof(args.token));
-    cache_enter(command_find_frame_info_cache_client, c, &args, sizeof(args));
+    cache_enter(command_find_frame_props_cache_client, c, &args, sizeof(args));
+}
+
+static void command_find_frame_props(char * token, Channel * c) {
+    CommandFindFrameInfo args;
+
+    json_read_string(&c->inp, args.id, sizeof(args.id));
+    json_test_char(&c->inp, MARKER_EOA);
+    args.addr = (ContextAddress)json_read_uint64(&c->inp);
+    json_test_char(&c->inp, MARKER_EOA);
+    json_test_char(&c->inp, MARKER_EOM);
+    args.props = 1;
+
+    strlcpy(args.token, token, sizeof(args.token));
+    cache_enter(command_find_frame_props_cache_client, c, &args, sizeof(args));
 }
 
 typedef struct CommandSymFileInfo {
@@ -1126,7 +1222,8 @@
     add_command_handler(proto, SYMBOLS, "list", command_list);
     add_command_handler(proto, SYMBOLS, "getArrayType", command_get_array_type);
     add_command_handler(proto, SYMBOLS, "getLocationInfo", command_get_location_info);
-    add_command_handler(proto, SYMBOLS, "findFrameInfo", command_find_frame_info);
+    add_command_handler(proto, SYMBOLS, "findFrameInfo", command_find_frame_info); /* Deprecated, use findFrameProps */
+    add_command_handler(proto, SYMBOLS, "findFrameProps", command_find_frame_props);
     add_command_handler(proto, SYMBOLS, "getSymFileInfo", command_get_sym_file_info);
     add_command_handler(proto, SYMBOLS, "getAddressInfo", command_get_address_info);
 }
diff --git a/agent/tcf/services/symbols.h b/agent/tcf/services/symbols.h
index 7f519de..63ff076 100644
--- a/agent/tcf/services/symbols.h
+++ b/agent/tcf/services/symbols.h
@@ -131,7 +131,7 @@
 } StackFrameRegisterLocation;
 
 typedef struct StackFrameInlinedSubroutine {
-    Symbol * sym;
+    const char * func_id;
     CodeArea area;
 } StackFrameInlinedSubroutine;
 
diff --git a/agent/tcf/services/symbols_elf.c b/agent/tcf/services/symbols_elf.c
index d6e510d..d879e5e 100644
--- a/agent/tcf/services/symbols_elf.c
+++ b/agent/tcf/services/symbols_elf.c
@@ -2324,7 +2324,7 @@
         }
     }
     object2symbol(NULL, o, &sym);
-    sub->sym = sym;
+    sub->func_id = tmp_strdup(symbol2id(sym));
     sub->area = area;
     sub->area.start_address = addr0;
     sub->area.end_address = addr1;
@@ -2334,15 +2334,6 @@
             buf->subs, sizeof(StackFrameInlinedSubroutine *) * buf_sub_max);
     }
     buf->subs[buf->sub_cnt++] = sub;
-    if (buf->addr < addr0) {
-        assert(buf->addr + buf->size > addr0);
-        buf->size = buf->addr + buf->size - addr0;
-        buf->addr = addr0;
-    }
-    if (buf->addr + buf->size > addr1) {
-        assert(addr1 > buf->addr);
-        buf->size = addr1 - buf->addr;
-    }
 }
 
 static void search_inlined_subroutine(Context * ctx, ObjectInfo * obj, UnitAddress * addr, StackTracingInfo * buf) {
@@ -2359,9 +2350,6 @@
         case TAG_catch_block:
         case TAG_subroutine:
         case TAG_subprogram:
-            if (!check_in_range(o, addr)) break;
-            search_inlined_subroutine(ctx, o, addr, buf);
-            break;
         case TAG_inlined_subroutine:
             if (o->mFlags & DOIF_ranges) {
                 DWARFCache * cache = get_dwarf_cache(addr->file);
@@ -2382,14 +2370,28 @@
                         else {
                             if (x_sec == NULL) x_sec = unit->mTextSection;
                             if (y_sec == NULL) y_sec = unit->mTextSection;
-                            if (x_sec == addr->section && y_sec == addr->section && addr->lt_addr >= base + x && addr->lt_addr < base + y) {
-                                ELF_File * file = unit->mFile;
-                                ContextAddress addr0 = elf_map_to_run_time_address(ctx, file, addr->section, base + x);
-                                ContextAddress addr1 = elf_map_to_run_time_address(ctx, file, addr->section, base + y);
+                            if (x_sec == addr->section && y_sec == addr->section && x < y) {
+                                ContextAddress addr0 = base + x - addr->lt_addr + addr->rt_addr;
+                                ContextAddress addr1 = base + y - addr->lt_addr + addr->rt_addr;
                                 if (addr0 <= addr->rt_addr && addr1 > addr->rt_addr) {
-                                    add_inlined_subroutine(o, unit, addr0, addr1, buf);
+                                    if (buf->addr < addr0) {
+                                        assert(buf->addr + buf->size > addr0);
+                                        buf->size = buf->addr + buf->size - addr0;
+                                        buf->addr = addr0;
+                                    }
+                                    if (buf->addr + buf->size > addr1) {
+                                        assert(addr1 > buf->addr);
+                                        buf->size = addr1 - buf->addr;
+                                    }
+                                    if (o->mTag == TAG_inlined_subroutine) add_inlined_subroutine(o, unit, addr0, addr1, buf);
                                     search_inlined_subroutine(ctx, o, addr, buf);
-                                    break;
+                                }
+                                else if (addr1 <= addr->rt_addr && addr1 > buf->addr) {
+                                    buf->size = buf->addr + buf->size - addr1;
+                                    buf->addr = addr1;
+                                }
+                                else if (addr0 > addr->rt_addr && addr0 < buf->addr + buf->size) {
+                                    buf->size = addr0 - buf->addr;
                                 }
                             }
                         }
@@ -2397,16 +2399,29 @@
                     dio_ExitSection();
                 }
             }
-            else if ((o->mFlags & DOIF_low_pc) && o->u.mCode.mHighPC.mAddr > o->u.mCode.mLowPC &&
-                    addr->lt_addr >= o->u.mCode.mLowPC && addr->lt_addr < o->u.mCode.mHighPC.mAddr &&
-                    o->u.mCode.mSection == addr->section) {
-                ELF_File * file = addr->unit->mFile;
-                ContextAddress addr0 = elf_map_to_run_time_address(ctx, file, addr->section, o->u.mCode.mLowPC);
-                ContextAddress addr1 = elf_map_to_run_time_address(ctx, file, addr->section, o->u.mCode.mHighPC.mAddr);
+            else if ((o->mFlags & DOIF_low_pc) && o->u.mCode.mHighPC.mAddr > o->u.mCode.mLowPC && o->u.mCode.mSection == addr->section) {
+                ContextAddress addr0 = o->u.mCode.mLowPC - addr->lt_addr + addr->rt_addr;
+                ContextAddress addr1 = o->u.mCode.mHighPC.mAddr - addr->lt_addr + addr->rt_addr;
                 if (addr0 <= addr->rt_addr && addr1 > addr->rt_addr) {
-                    add_inlined_subroutine(o, addr->unit, addr0, addr1, buf);
+                    if (buf->addr < addr0) {
+                        assert(buf->addr + buf->size > addr0);
+                        buf->size = buf->addr + buf->size - addr0;
+                        buf->addr = addr0;
+                    }
+                    if (buf->addr + buf->size > addr1) {
+                        assert(addr1 > buf->addr);
+                        buf->size = addr1 - buf->addr;
+                    }
+                    if (o->mTag == TAG_inlined_subroutine) add_inlined_subroutine(o, addr->unit, addr0, addr1, buf);
                     search_inlined_subroutine(ctx, o, addr, buf);
                 }
+                else if (addr1 <= addr->rt_addr && addr1 > buf->addr) {
+                    buf->size = buf->addr + buf->size - addr1;
+                    buf->addr = addr1;
+                }
+                else if (addr0 > addr->rt_addr && addr0 < buf->addr + buf->size) {
+                    buf->size = addr0 - buf->addr;
+                }
             }
             break;
         }
diff --git a/agent/tcf/services/symbols_proxy.c b/agent/tcf/services/symbols_proxy.c
index d843e33..e4765ce 100644
--- a/agent/tcf/services/symbols_proxy.c
+++ b/agent/tcf/services/symbols_proxy.c
@@ -31,6 +31,7 @@
 #include <tcf/framework/exceptions.h>
 #include <tcf/services/stacktrace.h>
 #include <tcf/services/memorymap.h>
+#include <tcf/services/linenumbers.h>
 #include <tcf/services/symbols.h>
 #include <tcf/services/vm.h>
 #if ENABLE_SymbolsMux
@@ -64,6 +65,8 @@
     LINK link_address[HASH_SIZE];
     LINK link_location[HASH_SIZE];
     int service_available;
+    int no_find_frame_info;
+    int no_find_frame_props;
 } SymbolsCache;
 
 /* Symbol properties cache */
@@ -146,6 +149,7 @@
     Context * ctx;
     uint64_t ip;
     StackTracingInfo sti;
+    int command_props;
     int disposed;
 } StackFrameCache;
 
@@ -477,6 +481,14 @@
         context_unlock(c->ctx);
         for (i = 0; i < c->sti.reg_cnt; i++) free_sft_sequence(c->sti.regs[i]);
         free_sft_sequence(c->sti.fp);
+        for (i = 0; i < c->sti.sub_cnt; i++) {
+            StackFrameInlinedSubroutine * info = c->sti.subs[i];
+            loc_free(info->area.directory);
+            loc_free(info->area.file);
+            loc_free(info->func_id);
+            loc_free(info);
+        }
+        loc_free(c->sti.subs);
         loc_free(c->sti.regs);
         loc_free(c);
     }
@@ -1511,6 +1523,10 @@
 static unsigned trace_regs_max = 0;
 static StackFrameRegisterLocation ** trace_regs = NULL;
 
+static unsigned trace_subs_cnt = 0;
+static unsigned trace_subs_max = 0;
+static StackFrameInlinedSubroutine ** trace_subs = NULL;
+
 static unsigned discriminant_cnt = 0;
 static unsigned discriminant_max = 0;
 static DiscriminantRange * discriminant_lst = NULL;
@@ -1768,6 +1784,62 @@
     }
 }
 
+static void read_inlined_subroutine_props(InputStream * inp, const char * name, void * args) {
+    StackFrameInlinedSubroutine * s = (StackFrameInlinedSubroutine *)args;
+    if (strcmp(name, "ID") == 0) s->func_id = json_read_alloc_string(inp);
+    else if (strcmp(name, "Area") == 0) read_code_area(inp, &s->area);
+    else json_skip_object(inp);
+}
+
+static void read_inlined_subroutine(InputStream * inp, void * args) {
+    if (trace_subs_cnt >= trace_subs_max) {
+        trace_subs_max += 16;
+        trace_subs = (StackFrameInlinedSubroutine **)loc_realloc(trace_subs, trace_subs_max * sizeof(StackFrameInlinedSubroutine *));
+    }
+    trace_subs[trace_subs_cnt] = (StackFrameInlinedSubroutine *)loc_alloc_zero(sizeof(StackFrameInlinedSubroutine));
+    json_read_struct(inp, read_inlined_subroutine_props, trace_subs[trace_subs_cnt++]);
+}
+
+static void read_stack_frame_fp(InputStream * inp, StackFrameCache * f) {
+    location_cmds.cnt = 0;
+    if (json_read_array(inp, read_location_command, NULL)) {
+        f->sti.fp = (StackFrameRegisterLocation *)loc_alloc(sizeof(StackFrameRegisterLocation) +
+            (location_cmds.cnt - 1) * sizeof(LocationExpressionCommand));
+        f->sti.fp->reg = NULL;
+        f->sti.fp->cmds_cnt = location_cmds.cnt;
+        f->sti.fp->cmds_max = location_cmds.cnt;
+        memcpy(f->sti.fp->cmds, location_cmds.cmds, location_cmds.cnt * sizeof(LocationExpressionCommand));
+    }
+}
+
+static void read_stack_frame_regs(InputStream * inp, StackFrameCache * f) {
+    trace_regs_cnt = 0;
+    if (json_read_struct(inp, read_stack_trace_register, NULL)) {
+        f->sti.reg_cnt = trace_regs_cnt;
+        f->sti.regs = (StackFrameRegisterLocation **)loc_alloc(trace_regs_cnt * sizeof(StackFrameRegisterLocation *));
+        memcpy(f->sti.regs, trace_regs, trace_regs_cnt * sizeof(StackFrameRegisterLocation *));
+    }
+}
+
+static void read_stack_frame_inlined(InputStream * inp, StackFrameCache * f) {
+    trace_subs_cnt = 0;
+    if (json_read_array(inp, read_inlined_subroutine, NULL)) {
+        f->sti.sub_cnt = trace_subs_cnt;
+        f->sti.subs = (StackFrameInlinedSubroutine **)loc_alloc(trace_subs_cnt * sizeof(StackFrameInlinedSubroutine *));
+        memcpy(f->sti.subs, trace_subs, trace_subs_cnt * sizeof(StackFrameInlinedSubroutine *));
+    }
+}
+
+static void read_stack_frame_props(InputStream * inp, const char * name, void * args) {
+    StackFrameCache * f = (StackFrameCache *)args;
+    if (strcmp(name, "CodeAddr") == 0) f->sti.addr = (ContextAddress)json_read_uint64(inp);
+    else if (strcmp(name, "CodeSize") == 0) f->sti.size = (ContextAddress)json_read_uint64(inp);
+    else if (strcmp(name, "FP") == 0) read_stack_frame_fp(inp, f);
+    else if (strcmp(name, "Regs") == 0) read_stack_frame_regs(inp, f);
+    else if (strcmp(name, "Inlined") == 0) read_stack_frame_inlined(inp, f);
+    else json_skip_object(inp);
+}
+
 static void validate_frame(Channel * c, void * args, int error) {
     Trap trap;
     StackFrameCache * f = (StackFrameCache *)args;
@@ -1777,49 +1849,38 @@
     if (set_trap(&trap)) {
         f->pending = NULL;
         if (!error) {
-            uint64_t addr, size;
             id2register_error = 0;
             error = read_errno(&c->inp);
-            addr = json_read_uint64(&c->inp);
-            json_test_char(&c->inp, MARKER_EOA);
-            size = json_read_uint64(&c->inp);
-            json_test_char(&c->inp, MARKER_EOA);
-            if (error || size == 0) {
-                f->sti.addr = f->ip & ~(uint64_t)3;
-                f->sti.size = 4;
+            if (f->command_props) {
+                json_read_struct(&c->inp, read_stack_frame_props, f);
+                json_test_char(&c->inp, MARKER_EOA);
             }
             else {
-                assert(addr <= f->ip);
-                assert(addr + size > f->ip);
-                f->sti.addr = (ContextAddress)addr;
-                f->sti.size = (ContextAddress)size;
+                /* Deprecated, use findFrameProps */
+                f->sti.addr = (ContextAddress)json_read_uint64(&c->inp);
+                json_test_char(&c->inp, MARKER_EOA);
+                f->sti.size = (ContextAddress)json_read_uint64(&c->inp);
+                json_test_char(&c->inp, MARKER_EOA);
+                read_stack_frame_fp(&c->inp, f);
+                json_test_char(&c->inp, MARKER_EOA);
+                read_stack_frame_regs(&c->inp, f);
+                json_test_char(&c->inp, MARKER_EOA);
             }
-            location_cmds.cnt = 0;
-            if (json_read_array(&c->inp, read_location_command, NULL)) {
-                f->sti.fp = (StackFrameRegisterLocation *)loc_alloc(sizeof(StackFrameRegisterLocation) +
-                    (location_cmds.cnt - 1) * sizeof(LocationExpressionCommand));
-                f->sti.fp->reg = NULL;
-                f->sti.fp->cmds_cnt = location_cmds.cnt;
-                f->sti.fp->cmds_max = location_cmds.cnt;
-                memcpy(f->sti.fp->cmds, location_cmds.cmds, location_cmds.cnt * sizeof(LocationExpressionCommand));
-            }
-            json_test_char(&c->inp, MARKER_EOA);
-            trace_regs_cnt = 0;
-            if (json_read_struct(&c->inp, read_stack_trace_register, NULL)) {
-                f->sti.reg_cnt = trace_regs_cnt;
-                f->sti.regs = (StackFrameRegisterLocation **)loc_alloc(trace_regs_cnt * sizeof(StackFrameRegisterLocation *));
-                memcpy(f->sti.regs, trace_regs, trace_regs_cnt * sizeof(StackFrameRegisterLocation *));
-            }
-            json_test_char(&c->inp, MARKER_EOA);
             json_test_char(&c->inp, MARKER_EOM);
             if (!error && id2register_error) error = id2register_error;
         }
+        if (error || f->sti.size == 0) {
+            f->sti.addr = (ContextAddress)f->ip;
+            f->sti.size = 1;
+        }
+        assert(f->sti.addr <= f->ip);
+        assert(f->sti.addr + f->sti.size > f->ip);
         clear_trap(&trap);
     }
     else {
         error = trap.error;
     }
-    if (get_error_code(error) != ERR_INV_COMMAND) f->error = get_error_report(error);
+    f->error = get_error_report(error);
     cache_notify_later(&f->cache);
     if (f->disposed) free_stack_frame_cache(f);
 }
@@ -1853,9 +1914,23 @@
 
     assert(f == NULL || f->pending == NULL);
 
+    if (f != NULL && f->error != NULL && get_error_code(set_error_report_errno(f->error)) == ERR_INV_COMMAND) {
+        if (f->command_props) {
+            syms->no_find_frame_props = 1;
+        }
+        else {
+            syms->no_find_frame_info = 1;
+        }
+        free_stack_frame_cache(f);
+        f = NULL;
+    }
+
     if (f == NULL && !syms->service_available) {
         /* nothing */
     }
+    else if (f == NULL && syms->no_find_frame_info && syms->no_find_frame_props) {
+        /* nothing */
+    }
     else if (f == NULL) {
         Channel * c = get_channel(syms);
         f = (StackFrameCache *)loc_alloc_zero(sizeof(StackFrameCache));
@@ -1864,7 +1939,15 @@
         context_lock(f->ctx = ctx);
         f->magic = MAGIC_FRAME;
         f->ip = ip;
-        f->pending = protocol_send_command(c, SYMBOLS, "findFrameInfo", validate_frame, f);
+        if (syms->no_find_frame_props) {
+            /* Deprecated, use findFrameProps */
+            f->pending = protocol_send_command(c, SYMBOLS, "findFrameInfo", validate_frame, f);
+            f->command_props = 0;
+        }
+        else {
+            f->pending = protocol_send_command(c, SYMBOLS, "findFrameProps", validate_frame, f);
+            f->command_props = 1;
+        }
         json_write_string(&c->out, f->ctx->id);
         write_stream(&c->out, 0);
         json_write_uint64(&c->out, ip);