On Tue, Sep 19, 2006 at 10:46:33AM +0900, Horms wrote:
>
> Hi Vivek,
>
> that seems generally fine to me. I'm not sure that I understand the
> finer points of the elf parsing that you are doing, but again, it
> seems fine. I've put some comments, mainly about formatting and the
> like, inline.
Hi Horms,
Thanks for such a detailed review and reply. I have taken care of most of
the comments. Pleas find the response inline. I am reposting the patches
in a separate mail.
> > +#if 0
> > + printf("%016Lx-%016Lx : %s",
> > + start, end, str);
> > +#endif
>
> I really don't like the use of #if 0. I know its elsewhere in the code,
> but I think it would be a lot nicer if we moved to something
> like #if DEBUG, which could be toggled by ./configure. Not really
> relevant to this patch, but I thought I would mention it anyway.
>
Agreed. I have moved the code under #ifdef DEBUG.
> > +
> > + fd = open(kcore, O_RDONLY);
> > + if (fd < 0) {
> > + fprintf(stderr, "Cannot open %s: %s\n", kcore, strerror(errno));
> > + goto backward_compatible;
> > + }
> > +#define KCORE_ELF_HEADERS_SIZE 4096
>
> Personally I'm much more comofortable with #defines going
> either towards the top a .c file, or in a .h file. Could you
> move this and the definition of KERN_VADDR_ALIGN below to
> one of these two locations, the .c one seems most appropriate
> here.
>
Ok. I have moved KCORE_ELF_HEADERS_SIZE in crashdump.h. KERN_VADDRA_ALIGN
I have moved to the top in .c file.
> > + size = KCORE_ELF_HEADERS_SIZE;
> > + buf = xmalloc(size);
>
> Is there is a reason buf needs to be on the heap rather than the stack?
> As it is a static size it seems easier just to declare it as
> a fixed-size array. For starters it means there is no chance
> of it leaking.
>
Now this code has moved inside function slurp_file_len() and it has
to allocate buf from heap so that calling function can make use of
that buffer.
> > + memset(buf, 0, size);
> > + progress = 0;
> > + while(progress < size) {
> > + result = read(fd, buf + progress, size - progress);
> > + if (result < 0) {
> > + if ((errno == EINTR) || (errno == EAGAIN))
> > + continue;
> > + die("read on %s of %ld bytes failed: %s\n",
> > + kcore, (size - progress)+ 0UL, strerror(errno));
> > + }
> > + if (result == 0)
> > + /* EOF */
> > + break;
> > + progress += result;
> > + }
>
> Is this kind of read X bytes untill you have X, EOF or error loop
> a common thing in kexec-tools? It might be worth breaking it out into
> some common code somewhere.
>
Point taken. Wrote a function slurp_file_len() on the lines of slurp_file().
This function just reads len bytes as specified by the caller and not the
whole of the file.
> > + result = close(fd);
> > + if (result < 0)
> > + die("Close of %s failed: %s\n", kcore, strerror(errno));
>
> The result of close() is checked here, but the result of fclose()
> is not checked in some code above. Is there a reason for this
> inconsistency?
>
Not intentional. Just I had copied the code from slurp_file() and
it was doing the check on close().
> > +
> > + /* Don't perform checks to make sure stated phdrs and shdrs are
> > + * actually present in the core file. It is not practical
> > + * to read the GB size file into a user space buffer, Given the
> > + * fact that we don't use any info from that.
> > + */
>
> That is true, but it is might be practical to memmap it.
> Have you given some thought to whether that is worthwile or not?
I tried it but /proc/kcore does not support mmapping it. Otherwise
its a good idea.
>
> > + ignore_elf_len_check = 1;
>
> Should ignore_elf_len_check be turned off again at some point,
> or alternatively changed into a parameter rather than a global?
Now I am turning it off.
Its a global for keeping the code changes less. If I make it a parameter
then I have to change whole lot of functions and code across arches due
to interdependencies. So for the time being I have kept it a separate
global. But if you think that it is absolute no-no programming practice,
then I will write a separate patch to make it a function parameter.
>
> > + result = build_elf_core_info(buf, size, &ehdr);
> > + if (result < 0) {
> > + fprintf(stderr, "ELF core (kcore) parse failed\n");
> > + goto backward_compatible;
>
> Could the backward_compatible handling be moved into a
> separate function, rather than a goto? It seems that
> only info would need to be passed.
>
Done. Added a new function hardcode_kernel_vaddr_size() to handle it.
> > + }
> > + /* Traverse through the Elf headers and find the region where
> > + * kernel is mapped. */
> > +#define KERN_VADDR_ALIGN 0x200000 /* 2MB */
> > + end_phdr = &ehdr.e_phdr[ehdr.e_phnum];
> > + for(phdr = ehdr.e_phdr; phdr != end_phdr; phdr++) {
> > + if (phdr->p_type == PT_LOAD) {
> > + unsigned long saddr = phdr->p_vaddr;
> > + unsigned long eaddr = phdr->p_vaddr + phdr->p_memsz;
> > + unsigned long size;
> > + /* Look for kernel text mapping header. */
>
> It seems like there is one tab too few for the indentation
> of the line above.
>
Done.
> > + if ((saddr >= __START_KERNEL_map) &&
> > + (eaddr <= __START_KERNEL_map + KERNEL_TEXT_SIZE)) {
>
> I think that the above lines should be indented as follows
>
> if ((saddr >= __START_KERNEL_map) &&
> (eaddr <= __START_KERNEL_map + KERNEL_TEXT_SIZE)) {
> ^ 2nd line is indented to start inside the
> relevant ( of the 1st line
>
Done.
> > + saddr = (saddr) & (~(KERN_VADDR_ALIGN - 1));
> > + info->kern_vaddr_start = saddr;
> > + size = eaddr - saddr;
> > + /* Align size to page size boundary. */
> > + size = (size + align - 1) & (~(align - 1));
> > + info->kern_size = size;
> > +#if 0
> > + printf("kernel vaddr = 0x%lx size = 0x%lx\n",
> > + saddr, size);
> > +#endif
> > + return 0;
> > + }
>
> I'm not sure that I understand the alingment that the above
> if statment is adding, but I guess its fine :-)
Actually /proc/kcore reports the vaddr of symbol _stext
and not actually the starting kernel virtual address in the program
header created for kernel text. Generally there is some code before symbol
_stext. Anyway I load the kernel at 2MB aligned boundary so I forced this
alignment to make sure a neat separate program header is created. Otherwise
in /proc/vmcore we will end up creating an header starting at and odd
address, something like 0xfffff....1f1.
> >
> > +/* This parameter can be set to force ELF phdr and shdr building routines
> > + * to skip the check on file length which make sure that data pointed by
> > + * phdrs and shdrs is actually present in the file. This has been
> > introduced
> > + * to handle the corner case of reading /proc/kcore. /proc/kcore can be
> > + * of huge size (GB, TB), depending on RAM size. It does not make sense
> > + * to read that whole core file just to extract some info from kcore ELF
> > + * headers.
> > + * This is hackish. Please suggest a better way to handle it.
> > + */
> > +int ignore_elf_len_check = 0;
> > +
>
> Is there a reason this is global, rather than being passed
> as an argument to the relevant functions?
See above.
>
> > uint16_t elf16_to_cpu(const struct mem_ehdr *ehdr, uint16_t value)
> > {
> > if (ehdr->ei_data == ELFDATA2LSB) {
> > @@ -420,12 +431,14 @@ static int build_mem_phdrs(const char *b
> > * they are safe to use.
> > */
> > phdr = &ehdr->e_phdr[i];
> > - if ((phdr->p_offset + phdr->p_filesz) > len) {
> > - /* The segment does not fit in the buffer */
> > - if (probe_debug) {
> > - fprintf(stderr, "ELF segment not in file\n");
> > + if (!ignore_elf_len_check) {
> > + if ((phdr->p_offset + phdr->p_filesz) > len) {
> > + /* The segment does not fit in the buffer */
> > + if (probe_debug) {
> > + fprintf(stderr, "ELF segment not in
> > file\n");
> > + }
> > + return -1;
> > }
> > - return -1;
> > }
> > if ((phdr->p_paddr + phdr->p_memsz) < phdr->p_paddr) {
> > /* The memory address wraps */
>
> I think the above (mostly whitespace) change could be simplified to
> the following, which has the advantage of not being so heavily
> nested.
>
Done.
> > /* The memory address wraps */
>
> Again, I think the following is a bit simpler.
>
Done.
Thanks
Vivek
_______________________________________________
fastboot mailing list
[email protected]
https://lists.osdl.org/mailman/listinfo/fastboot