Skip to main content
summaryrefslogblamecommitdiffstats
blob: b9619d4bb52f90057f1eabc4e5e604d3c1035371 (plain) (tree)
1
2
3
4
5
6
7
8
9
                                                                                
                                                                

                                                                        


                                                                           
                                                       
                                                    
                                                                          
  


                                                                                 






                                                                              
                       
 
                                                                                           



                   



                                     

                                 
                                     

                                             



                                               
 





























                                                                                              
                                                                           
                                                                       




                                                   

                                                           
                   
                      
                        
                                 

                                         
                                       
                                               
                                                        
                                                
 
                                                                                                   



                                               
         
              
                                     
                                                           

                                                                        

                                                      
                                                                        

                                                      
                                                                      
                                                    
                                                                    

                                           

         
 






                    




                        
                                                                                                                                  
                
                      
                     

                         

                                     
 



                                                           

                                   
                                                
                                      
 
                                                                                                                 



                                       




                                                                                           
                                                                   
                                                               


                                                                   
                                                                            
                                                  
                                              




                                                
                                                                            
                                                  
                                              


                                         
                                                                                            
                                               

                                                                             
                                                  






                                 

                  
                              

             
              
                                     
         

                                       
                                                                                      














                                                                                                                         

     
                                 
                                                                                             
                          
 

                                           
                                                              
                                              
                                                            
                                            



                                               
                                       
                                               
                                                                         
         
     
 




                    

 

                                                                               


                                                  

 
                                                                                                    
/*******************************************************************************
 * Copyright (c) 2007, 2014 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 <tcf/config.h>

#if SERVICE_LineNumbers && (!ENABLE_LineNumbersProxy || ENABLE_LineNumbersMux) && ENABLE_PE

#include <errno.h>
#include <assert.h>
#include <stdio.h>
#include <tcf/framework/json.h>
#include <tcf/framework/protocol.h>
#include <tcf/framework/context.h>
#include <tcf/framework/exceptions.h>
#include <tcf/framework/cache.h>
#include <tcf/services/pathmap.h>
#include <tcf/services/linenumbers.h>
#include <system/Windows/tcf/windbgcache.h>
#include <system/Windows/tcf/context-win32.h>
#if ENABLE_LineNumbersMux
#define LINENUMBERS_READER_PREFIX win32_reader_
#include <tcf/services/linenumbers_mux.h>
#endif

static int compare_path(Channel * chnl, Context * ctx, const char * file, const char * name) {
    int i, j;
    char * full_name = NULL;

    if (file == NULL) return 0;
    if (name == NULL) return 0;

    while (file[0] == '.') {
        if (file[1] == '.' && file[2] == '/') file += 3;
        else if (file[1] == '/') file += 2;
        else break;
    }
    i = strlen(file);

    full_name = canonic_path_map_file_name(name);
    j = strlen(full_name);
    if (i <= j && strcmp(file, full_name + j - i) == 0) return 1;
#if SERVICE_PathMap
    {
        char * s = apply_path_map(chnl, ctx, full_name, PATH_MAP_TO_CLIENT);
        if (s != full_name) {
            full_name = canonic_path_map_file_name(s);
            j = strlen(full_name);
            if (i <= j && strcmp(file, full_name + j - i) == 0) return 1;
        }
    }
#endif
    return 0;
}

int line_to_address(Context * ctx, const 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) {
        CodeArea area;
        LONG offset = 0;
        IMAGEHLP_LINE64 img_line;
        Channel * chnl = cache_channel();

        memset(&area, 0, sizeof(area));
        memset(&img_line, 0, sizeof(img_line));
        img_line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
        file = canonic_path_map_file_name(file);

        if (!SymGetLineFromName64(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_LINE64 img_next;
            memcpy(&img_next, &img_line, sizeof(img_next));
            img_next.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
            if (!SymGetLineNext64(get_context_handle(ctx), &img_next)) {
                err = set_win32_errno(GetLastError());
            }
            else if (compare_path(chnl, ctx, file, img_line.FileName)) {
                area.file = img_line.FileName;
                area.start_line = img_line.LineNumber;
                area.start_address = (ContextAddress)img_line.Address;
                area.end_line = img_next.LineNumber;
                area.end_address = (ContextAddress)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_LINE64 line;
    IMAGEHLP_LINE64 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_LINE64);
    if (addr0 >= addr1) not_found = 1;

    while (err == 0 && not_found == 0 && !SymGetLineFromAddr64(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 && !SymGetLineNext64(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 = (ContextAddress)line.Address;
            area.start_line = line.LineNumber;
            area.end_address = (ContextAddress)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 (!SymGetLineNext64(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);
#if ENABLE_LineNumbersMux
    add_line_numbers_reader(&line_numbers_reader);
#endif
}

#endif /* SERVICE_LineNumbers && (!ENABLE_LineNumbersProxy || ENABLE_LineNumbersMux) && ENABLE_PE */

Back to the top