3 * Written by Jan Roeloffzen
5 * - Initialization, translation and main loop
19 #include "log2lines.h"
25 static FILE *dbgIn
= NULL
;
26 static FILE *dbgOut
= NULL
;
27 static FILE *conIn
= NULL
;
28 static FILE *conOut
= NULL
;
29 static const char *kdbg_prompt
= KDBG_PROMPT
;
30 static const char *kdbg_cont
= KDBG_CONT
;
43 memset(&lastLine
, 0, sizeof(LINEINFO
));
47 log_file(FILE *outFile
, char *fileName
, int line
)
49 int i
= 0, min
= 0, max
= 0;
53 strcpy(s
, opt_SourcesPath
);
56 max
= line
+ opt_SrcPlus
;
57 if ((src
= fopen(s
, "r")))
59 min
= line
- opt_Source
;
60 min
= (min
< 0) ? 0 : min
;
61 while (i
< max
&& fgets(s
, LINESIZE
, src
))
66 log(outFile
, "| ----\n");
67 log(outFile
, "| %4.4d %s", i
+ 1, s
);
73 log(outFile
, "| S--- source has only %d lines! (check source/revision)\n", i
);
76 l2l_dbg(1, "Can't open: %s (check " SOURCES_ENV
")\n", s
);
80 logSource(FILE *outFile
)
82 log_file(outFile
, lastLine
.file1
, lastLine
.nr1
);
85 log(outFile
, "| ---- [%u] ----\n", lastLine
.nr2
);
86 log_file(outFile
, lastLine
.file2
, lastLine
.nr2
);
91 reportSource(FILE *outFile
)
100 report(FILE *outFile
)
102 reportRevision(outFile
);
103 reportSource(outFile
);
109 print_offset(void *data
, size_t offset
, char *toString
)
111 PSYMBOLFILE_HEADER RosSymHeader
= (PSYMBOLFILE_HEADER
)data
;
112 PROSSYM_ENTRY e
= NULL
;
113 PROSSYM_ENTRY e2
= NULL
;
114 int bFileOffsetChanged
= 0;
116 char *Strings
= (char *)data
+ RosSymHeader
->StringsOffset
;
119 e
= find_offset(data
, offset
);
122 e2
= find_offset(data
, offset
- 1);
133 /* replaced (transparantly), but updated stats */
138 strcpy(lastLine
.file1
, &Strings
[e
->FileOffset
]);
139 strcpy(lastLine
.func1
, &Strings
[e
->FunctionOffset
]);
140 lastLine
.nr1
= e
->SourceLine
;
141 sources_entry_create(&sources
, lastLine
.file1
, SVN_PREFIX
);
145 strcpy(lastLine
.file2
, &Strings
[e2
->FileOffset
]);
146 strcpy(lastLine
.func2
, &Strings
[e2
->FunctionOffset
]);
147 lastLine
.nr2
= e2
->SourceLine
;
148 sources_entry_create(&sources
, lastLine
.file2
, SVN_PREFIX
);
149 bFileOffsetChanged
= e
->FileOffset
!= e2
->FileOffset
;
150 if (e
->FileOffset
!= e2
->FileOffset
|| e
->FunctionOffset
!= e2
->FunctionOffset
)
154 * - "%.0s" displays nothing, but processes argument
155 * - bFileOffsetChanged implies always display 2nd SourceLine even if the same
156 * - also for FunctionOffset
159 if (bFileOffsetChanged
)
165 if (e
->SourceLine
!= e2
->SourceLine
|| bFileOffsetChanged
)
171 if (e
->FunctionOffset
!= e2
->FunctionOffset
|| bFileOffsetChanged
)
172 strcat(fmt
, "[%s])");
174 strcat(fmt
, "%.0s)");
177 { // put in toString if provided
178 snprintf(toString
, LINESIZE
, fmt
,
179 &Strings
[e
->FileOffset
],
180 &Strings
[e2
->FileOffset
],
181 (unsigned int)e
->SourceLine
,
182 (unsigned int)e2
->SourceLine
,
183 &Strings
[e
->FunctionOffset
],
184 &Strings
[e2
->FunctionOffset
]);
190 &Strings
[e
->FileOffset
],
191 &Strings
[e2
->FileOffset
],
192 (unsigned int)e
->SourceLine
,
193 (unsigned int)e2
->SourceLine
,
194 &Strings
[e
->FunctionOffset
],
195 &Strings
[e2
->FunctionOffset
]);
201 { // put in toString if provided
202 snprintf(toString
, LINESIZE
, "%s:%u (%s)",
203 &Strings
[e
->FileOffset
],
204 (unsigned int)e
->SourceLine
,
205 &Strings
[e
->FunctionOffset
]);
209 printf("%s:%u (%s)\n",
210 &Strings
[e
->FileOffset
],
211 (unsigned int)e
->SourceLine
,
212 &Strings
[e
->FunctionOffset
]);
221 process_data(const void *FileData
, size_t offset
, char *toString
)
225 PIMAGE_SECTION_HEADER PERosSymSectionHeader
= get_sectionheader((char *)FileData
);
226 if (!PERosSymSectionHeader
)
229 res
= print_offset((char *)FileData
+ PERosSymSectionHeader
->PointerToRawData
, offset
, toString
);
233 sprintf(toString
, "??:0");
236 l2l_dbg(1, "Offset not found: %x\n", (unsigned int)offset
);
237 summ
.offset_errors
++;
244 process_file(const char *file_name
, size_t offset
, char *toString
)
250 FileData
= load_file(file_name
, &FileSize
);
253 l2l_dbg(0, "An error occured loading '%s'\n", file_name
);
257 res
= process_data(FileData
, offset
, toString
);
264 translate_file(const char *cpath
, size_t offset
, char *toString
)
267 LIST_MEMBER
*pentry
= NULL
;
271 dpath
= path
= convert_path(cpath
);
275 // The path could be absolute:
276 if (get_ImageBase(path
, &base
))
278 pentry
= entry_lookup(&cache
, path
);
282 base
= pentry
->ImageBase
;
283 if (base
== INVALID_BASE
)
285 l2l_dbg(1, "No, or invalid base address: %s\n", path
);
291 l2l_dbg(1, "Not found in cache: %s\n", path
);
298 res
= process_file(path
, offset
, toString
);
306 translate_char(int c
, FILE *outFile
)
314 remove_mark(char *Line
)
316 if (Line
[1] == ' ' && Line
[2] == '<')
317 if (Line
[0] == '*' || Line
[0] == '?')
323 translate_line(FILE *outFile
, char *Line
, char *path
, char *LineOut
)
327 char *sep
, *tail
, *mark
, *s
;
335 s
= remove_mark(Line
);
338 /* Strip all lines added by this tool: */
340 if (sscanf(s
, "| %s", buf
) == 1)
341 if (buf
[0] == '0' || strcmp(buf
, "----") == 0 || strcmp(buf
, "L2L-") == 0 || strcmp(buf
, "S---") == 0 || strcmp(buf
, "R---") == 0 || atoi(buf
))
345 sep
= strchr(s
, ':');
349 cnt
= sscanf(s
, "<%s %x%c", path
, &offset
, &ch
);
352 if (cnt
== 3 && ch
== ' ')
354 tail
= strchr(s
, '>');
355 tail
= tail
? tail
- 1 : tail
;
356 if (tail
&& tail
[0] == ')' && tail
[1] == '>')
360 mark
= opt_mark
? "* " : "";
361 if (opt_redo
&& !(res
= translate_file(path
, offset
, LineOut
)))
363 log(outFile
, "%s<%s:%x (%s)>%s", mark
, path
, offset
, LineOut
, tail
);
368 log(outFile
, "%s<%s:%x>%s", mark
, path
, offset
, tail
);
374 mark
= opt_Mark
? "? " : "";
381 if (!opt_undo
|| opt_redo
)
383 if (cnt
== 3 && ch
== '>')
385 tail
= strchr(s
, '>') + 1;
386 if (!(res
= translate_file(path
, offset
, LineOut
)))
388 mark
= opt_mark
? "* " : "";
389 log(outFile
, "%s<%s:%x (%s)>%s", mark
, path
, offset
, LineOut
, tail
);
394 mark
= opt_Mark
? "? " : "";
404 *sep
= ':'; // restore because not translated
405 log(outFile
, "%s%s", mark
, s
);
407 memset(Line
, '\0', LINESIZE
); // flushed
411 translate_files(FILE *inFile
, FILE *outFile
)
413 char Line
[LINESIZE
+ 1];
414 char path
[LINESIZE
+ 1];
415 char LineOut
[LINESIZE
+ 1];
419 const char *pc
= kdbg_cont
;
420 const char *p
= kdbg_prompt
;
421 const char *p_eos
= p
+ sizeof(KDBG_PROMPT
) - 1; //end of string pos
423 memset(Line
, '\0', LINESIZE
+ 1);
426 while ((c
= fgetc(inFile
)) != EOF
)
430 ch
= (unsigned char)c
;
436 if ( strncmp(Line
, KDBG_DISCARD
, sizeof(KDBG_DISCARD
)-1) == 0 )
438 memset(Line
, '\0', LINESIZE
); // flushed
442 Line
[1] = handle_escape_cmd(outFile
, Line
, path
, LineOut
);
443 if (Line
[1] != KDBG_ESC_CHAR
)
447 // kdbg prompt, so already echoed char by char
448 memset(Line
, '\0', LINESIZE
);
449 translate_char(c
, outFile
);
453 if (match_line(outFile
, Line
))
455 translate_line(outFile
, Line
, path
, LineOut
);
456 translate_char(c
, outFile
);
474 translate_line(outFile
, Line
, path
, LineOut
);
482 translate_line(outFile
, Line
, path
, LineOut
);
486 translate_line(outFile
, Line
, path
, LineOut
);
487 translate_char(c
, outFile
);
491 translate_char(c
, outFile
);
502 translate_char(c
, outFile
);
506 translate_line(outFile
, Line
, path
, LineOut
);
512 translate_line(outFile
, Line
, path
, LineOut
);
513 translate_char(c
, outFile
);
519 translate_char(c
, outFile
);
523 { // Line by line, slightly faster but less interactive
524 while (fgets(Line
, LINESIZE
, inFile
) != NULL
)
530 translate_line(outFile
, Line
, path
, LineOut
);
534 log(outFile
, "%s", Line
);
538 if (opt_Revision
&& (strstr(opt_Revision
, "regscan") == opt_Revision
))
540 char *s
= strchr(opt_Revision
, ',');
544 revinfo
.range
= atoi(s
);
551 stat_print(outFile
, &summ
);
553 stat_print(logFile
, &summ
);
560 main(int argc
, const char **argv
)
571 memset(&cache
, 0, sizeof(LIST
));
572 memset(&sources
, 0, sizeof(LIST
));
574 memset(&revinfo
, 0, sizeof(REVINFO
));
577 optInit
= optionInit(argc
, argv
);
578 optCount
= optionParse(argc
, argv
);
580 if (optCount
< 0 || optInit
< 0)
588 if (opt_Revision
&& (strcmp(opt_Revision
, "update") == 0))
590 res
= updateSvnlog();
594 if (check_directory(opt_force
))
600 create_cache(opt_force
, 0);
608 l2l_dbg(4, "Cache read complete\n");
610 if (set_LogFile(&logFile
))
615 l2l_dbg(4, "opt_logFile processed\n");
619 l2l_dbg(3, "Command line: \"%s\"\n",opt_Pipe
);
621 if (!(dbgIn
= POPEN(opt_Pipe
, "r")))
623 dbgIn
= stdin
; //restore
624 l2l_dbg(0, "Could not popen '%s' (%s)\n", opt_Pipe
, strerror(errno
));
629 l2l_dbg(4, "opt_Pipe processed\n");
632 { // translate {<exefile> <offset>}
634 const char *exefile
= NULL
;
635 const char *offset
= NULL
;
636 char Line
[LINESIZE
+ 1];
637 char PathBuffer
[LINESIZE
+ 1];
638 char LineOutBuffer
[LINESIZE
+ 1];
640 // TODO: Re-use one translate_files(), instead of repeated translate_line().
643 offset
= argv
[optCount
+ i
++];
644 if (isOffset(offset
))
648 l2l_dbg(2, "translating %s %s\n", exefile
, offset
);
650 snprintf(Line
, LINESIZE
, "<%s:%s>\n", exefile
, offset
);
651 translate_line(conOut
, Line
, PathBuffer
, LineOutBuffer
);
656 l2l_dbg(0, "<exefile> expected\n");
663 // Not an offset so must be an exefile:
669 { // translate logging from stdin
670 translate_files(dbgIn
, conOut
);
680 // See optionParse().
694 list_clear(&sources
);