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

                                                                        


                                                                           
                                                       
                                                    
                                                                          
  


                                                                                 






                                                                              
                       
 
                                                                                    



                   




                                     

                                             
 
                                                                     
                                                                       




                                                   

                                                           
                   
                        
                               
                      
                                               
                                       

                                                      
                                                                                                 



                                               
         
              

                                                           
                                                                      









                                                      

         
 






                    




                        
                                                                                                                                  
                
                      


                       

                                     
 



                                                           


                                              
                                      
 
                                                                                                               



                                       




                                                                                           
                                                                   
                                                               


                                                                   
                                                                            
                                                  
                                              




                                                
                                                                            
                                                  
                                              


                                         
                                                                                            
                                               

                                                                             
                                                  






                                 

                  
                              

             
              
                                     
         

                                       
                                                                                    














                                                                                                                         

     
                                 
                                                                                             
                          
 





                                              



                                               
                                       
                                               
                                                                       
         
     
 




                    

 



                                                                               
                                                                                                
/*******************************************************************************
 * 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 <tcf/config.h>

#if SERVICE_LineNumbers && !ENABLE_LineNumbersProxy && defined(WIN32) && !ENABLE_ELF

#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/services/linenumbers.h>
#include <system/Windows/tcf/windbgcache.h>
#include <system/Windows/tcf/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